{"id":478195,"date":"2026-05-01T05:40:44","date_gmt":"2026-05-01T05:40:44","guid":{"rendered":"https:\/\/savepearlharbor.com\/?p=478195"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=478195","title":{"rendered":"\u041c\u043e\u0439 \u043e\u043f\u044b\u0442 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 Sentry self-hosted"},"content":{"rendered":"<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041f\u0440\u0438\u0432\u0435\u0442! \u041c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u0414\u0430\u043d\u0438\u0438\u043b \u0422\u043a\u0430\u0447\u0435\u043d\u043a\u043e, \u044f \u0432\u0435\u0431\u2011\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0432 \u0418\u0422\u2011\u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438 \u00ab\u0410\u043a\u0442\u0438\u0432\u0438\u043a\u0430\u00bb. \u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043f\u043e\u0434\u0435\u043b\u044e\u0441\u044c \u043e\u043f\u044b\u0442\u043e\u043c \u0440\u0430\u0437\u0432\u0451\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f Sentry self\u2011hosted \u0434\u043b\u044f \u0432\u044b\u0441\u043e\u043a\u043e\u043d\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u043e\u0431\u0438\u043b\u0438\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u043e\u0432 \u043f\u043e SaaS\u2011\u0432\u0435\u0440\u0441\u0438\u0438, \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0445 \u0433\u0430\u0439\u0434\u043e\u0432 \u043f\u043e self\u2011hosted\u2011\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0435 \u043f\u043e\u0447\u0442\u0438 \u043d\u0435\u0442 \u2014 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0441 \u0443\u0447\u0451\u0442\u043e\u043c \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439 \u043a \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0438 \u043e\u0442\u043a\u0430\u0437\u043e\u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u043e\u0441\u0442\u0438.<\/p>\n<p>\u041c\u044b \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u043b\u0438\u0441\u044c \u0441 \u0440\u044f\u0434\u043e\u043c \u043f\u0440\u043e\u0431\u043b\u0435\u043c: \u043d\u0435\u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u044c\u044e \u043d\u0430 \u0431\u0430\u0437\u043e\u0432\u043e\u043c \u0445\u043e\u0441\u0442\u0438\u043d\u0433\u0435, \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435\u043c \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0430 HTTP\u2011\u043e\u0448\u0438\u0431\u043e\u043a \u0438 \u0431\u044b\u0441\u0442\u0440\u044b\u043c \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435\u043c \u0434\u0438\u0441\u043a\u0430. \u041f\u043e\u0434 \u043a\u0430\u0442\u043e\u043c \u0440\u0430\u0437\u0431\u0435\u0440\u0443 \u043a\u0430\u0436\u0434\u0443\u044e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443, \u043f\u043e\u043a\u0430\u0436\u0443 \u043a\u043e\u0434 \u0440\u0435\u0448\u0435\u043d\u0438\u0439 \u0438 \u0434\u0430\u043c \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u0442\u0435\u0445, \u043a\u0442\u043e \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u0435\u0442 \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c Sentry \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e.<\/p>\n<p>\u0421\u0442\u0430\u0442\u044c\u044f \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0435\u0437\u043d\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c \u0438 DevOps\u2011\u0438\u043d\u0436\u0435\u043d\u0435\u0440\u0430\u043c \u0431\u0435\u0437 \u043e\u043f\u044b\u0442\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 self\u2011hosted Sentry.<\/p>\n<h2>\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 1. \u041d\u0435\u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043d\u0430 \u0431\u0430\u0437\u043e\u0432\u043e\u043c \u0445\u043e\u0441\u0442\u0438\u043d\u0433\u0435<\/h2>\n<p>\u0412\u0441\u0451 \u043d\u0430\u0447\u0430\u043b\u043e\u0441\u044c \u0441 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043d\u0430 \u043d\u0430\u0448\u0435\u043c \u0431\u0430\u0437\u043e\u0432\u043e\u043c \u0445\u043e\u0441\u0442\u0438\u043d\u0433\u0435 \u0432\u043e\u0437\u043d\u0438\u043a\u043b\u0438 \u043e\u0448\u0438\u0431\u043a\u0438: Sentry \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e \u043d\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u043b\u0441\u044f \u0438\u0437\u2011\u0437\u0430 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0435\u0439 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438. \u041d\u0435\u043b\u044c\u0437\u044f \u0431\u044b\u043b\u043e \u0434\u0430\u0436\u0435 \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u044b \u043f\u0435\u0440\u0435\u0435\u0445\u0430\u043b\u0438 \u043d\u0430 \u0434\u0440\u0443\u0433\u043e\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u2014 \u0438 \u0442\u043e\u0433\u0434\u0430 \u0432\u0441\u0451 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c.<\/p>\n<p>\u041d\u043e \u0442\u0443\u0442 \u043c\u0435\u043d\u044f \u0442\u043e\u0436\u0435 \u043f\u043e\u0434\u0436\u0438\u0434\u0430\u043b\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b: \u043f\u0430\u043c\u044f\u0442\u044c \u0431\u044b\u0441\u0442\u0440\u043e \u0437\u0430\u0431\u0438\u0432\u0430\u043b\u0430\u0441\u044c, \u0438 \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043b\u043e\u0433\u0430\u043c\u0438 \u0432 \u0442\u043e\u043c \u0436\u0435 ClickHouse \u0438\u043b\u0438 \u0444\u0430\u0439\u043b\u0430\u043c\u0438 \u0440\u0435\u043f\u043b\u0435\u0435\u0432, \u0430 \u043b\u043e\u0433\u0430\u043c\u0438 \u0432 Kafka.<\/p>\n<p>\u0417\u0430 \u0432\u0440\u0435\u043c\u044f \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439 \u043a \u0434\u0435\u043c\u043e\u0432\u0435\u0440\u0441\u0438\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 (\u0430 \u0435\u0439 \u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d\u043e\u0435 \u0447\u0438\u0441\u043b\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u043e\u0432\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439) Sentry \u043f\u0430\u0434\u0430\u043b \u0434\u0432\u0430 \u0440\u0430\u0437\u0430, \u0430 \u0434\u0435\u043c\u043e-\u0432\u0435\u0440\u0441\u0438\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0433\u0440\u0443\u0437\u0438\u043b\u0430\u0441\u044c \u043e\u0447\u0435\u043d\u044c \u0434\u043e\u043b\u0433\u043e.\u00a0<\/p>\n<p>\u041a\u043e\u0433\u0434\u0430 Sentry \u043f\u0430\u0434\u0430\u043b, \u0441\u0430\u0439\u0442 \u0433\u0440\u0443\u0437\u0438\u043b\u0441\u044f \u043e\u0447\u0435\u043d\u044c \u0434\u043e\u043b\u0433\u043e \u2014 \u043e\u043a\u043e\u043b\u043e 30\u201340 \u0441\u0435\u043a\u0443\u043d\u0434. \u042d\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u043b\u043e \u043f\u043e\u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u043a\u043b\u0438\u0435\u043d\u0442 \u043f\u044b\u0442\u0430\u043b\u0441\u044f \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c JS\u2011\u0441\u043a\u0440\u0438\u043f\u0442\u044b \u0441 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 CDN, \u043d\u043e \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 Sentry. \u0417\u0430\u043f\u0440\u043e\u0441\u044b \u0437\u0430\u0432\u0438\u0441\u0430\u043b\u0438 \u043d\u0430 \u0442\u0430\u0439\u043c\u0430\u0443\u0442\u0430\u0445, \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b.<\/p>\n<p>\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438: 32 \u0413\u0411 RAM, 4 \u044f\u0434\u0440\u0430 CPU, 40 \u0413\u0411 SSD. \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438 \u0434\u043e \u0430\u0436\u0438\u043e\u0442\u0430\u0436\u0430 \u0441 \u0446\u0435\u043d\u0430\u043c\u0438 \u043d\u0430 \u043f\u0430\u043c\u044f\u0442\u044c \u2014 \u043f\u043e\u0442\u043e\u043c \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0443\u043c\u0435\u043d\u044c\u0448\u0438\u0442\u044c RAM \u0434\u043e 16-24 \u0413\u0411, \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0442\u044c SSD \u0434\u043e 100\u0413\u0411 \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c swap-\u0444\u0430\u0439\u043b, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u0435\u0440\u0435\u043f\u043b\u0430\u0447\u0438\u0432\u0430\u0442\u044c.\u00a0<\/p>\n<h3>\u041b\u0430\u0439\u0444\u0445\u0430\u043a\u0438 \u0434\u043b\u044f \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0441\u0430\u0439\u0442\u0430, \u043a\u043e\u0433\u0434\u0430 \u0441\u0435\u043d\u0442\u0440\u0438 \u043d\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d<\/h3>\n<p>\u0414\u0430\u0436\u0435 \u043f\u0440\u0438 self\u2011hosted \u0440\u0435\u0448\u0435\u043d\u0438\u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b \u0441\u0431\u043e\u0438: DDoS\u2011\u0430\u0442\u0430\u043a\u0438, \u043f\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0430, \u043e\u0448\u0438\u0431\u043a\u0438 \u041f\u041e. \u0414\u0435\u043b\u044e\u0441\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u0435\u043d\u043d\u044b\u043c\u0438 \u043c\u043d\u043e\u0439 \u0441\u043f\u043e\u0441\u043e\u0431\u0430\u043c\u0438 \u043c\u0438\u043d\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u0432\u043b\u0438\u044f\u043d\u0438\u0435, \u0447\u0442\u043e\u0431\u044b \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u0434\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u0430\u0439\u0442\u0430, \u0434\u0430\u0436\u0435 \u043f\u0440\u0438 \u043f\u043e\u043b\u043d\u043e\u043c \u043e\u0442\u043a\u0430\u0437\u0435 Sentry.<\/p>\n<p><strong>\u0425\u0430\u043a 1. \u041b\u043e\u043a\u0430\u043b\u044c\u043d\u0430\u044f \u0443\u0440\u0435\u0437\u0430\u043d\u043d\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f JS\u2011\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438<\/strong><\/p>\n<p>\u042f \u0441\u043a\u0430\u0447\u0430\u043b JS-\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 Sentry \u0438 \u0445\u0440\u0430\u043d\u0438\u043b \u0435\u0451 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e \u0432 \u0443\u0440\u0435\u0437\u0430\u043d\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438. \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u2014 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u0430\u044f \u0438 \u0431\u0435\u0437 \u0437\u0430\u0432\u0438\u0441\u0430\u043d\u0438\u0439.<\/p>\n<p><strong>\u0425\u0430\u043a 2. \u00a0\u0422\u0430\u0439\u043c\u0430\u0443\u0442\u044b \u043d\u0430 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f<\/strong><\/p>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043a\u043e\u0434 \u0441 \u0442\u0430\u0439\u043c\u0430\u0443\u0442\u0430\u043c\u0438 \u043d\u0430 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u043f\u043e\u0432\u0435\u0440\u0445 SDK, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0440\u044b\u0432\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043a Sentry, \u0435\u0441\u043b\u0438 \u043e\u043d\u0438 \u0434\u043b\u044f\u0442\u0441\u044f \u0434\u043e\u043b\u044c\u0448\u0435 300 \u043c\u0438\u043b\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434.<\/p>\n<p>\u042d\u0442\u043e \u043f\u0440\u0435\u0434\u043e\u0442\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043f\u0435\u0440\u0435\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043e\u0447\u0435\u0440\u0435\u0434\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u043e\u0442\u0437\u044b\u0432\u0447\u0438\u0432\u043e\u0441\u0442\u044c \u0441\u0430\u0439\u0442\u0430.<\/p>\n<pre><code>     const SENTRY_TIMEOUT_MS = 300;        function makeCustomTimeoutTransport(options) {            \/\/ The 'makeRequest' function is the core where you control the fetch call.            function makeRequest(request) {                const controller = new AbortController();                const timeoutId = setTimeout(() =&gt; controller.abort(), SENTRY_TIMEOUT_MS); \/\/ 3-second timeout                const requestOptions = {                    body: request.body,                    method: 'POST',                    referrerPolicy: 'origin',                    headers: options.headers,                    signal: controller.signal, \/\/ &lt;-- Connect the AbortController                    ...options.fetchOptions,                };                \/\/ Return the fetch promise. It will be rejected if it times out.                return fetch(options.url, requestOptions)                    .then(response =&gt; {                        clearTimeout(timeoutId); \/\/ Clear timer on success                        return {                            statusCode: response.status,                            headers: {                                'x-sentry-rate-limits': response.headers.get('X-Sentry-Rate-Limits'),                                'retry-after': response.headers.get('Retry-After'),                            },                        };                    })                    .catch(error =&gt; {                        clearTimeout(timeoutId);                        if (error.name === 'AbortError') {                            console.warn('Sentry event dropped due to send timeout.');                            error.message = 'Sentry event dropped due to send timeout.';                        }                        throw error; \/\/ Re-throw to let the SDK handle the failure                    });            }            \/\/ Use the official helper to build a compliant transport.            return Sentry.createTransport(options, makeRequest);        }        Sentry.init({            transport: makeCustomTimeoutTransport,\u2026        });<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:87px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u042d\u0442\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043c\u044b \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043b\u0438 \u043d\u0430 \u043f\u0440\u043e\u0434\u0435.\u00a0<\/p>\n<p><strong>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442:<\/strong> \u043f\u043e\u0441\u043b\u0435 \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044f \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043b\u043e \u0437\u0430\u0431\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u043b\u043e\u0433 \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u044b\u043c\u0438 \u043f\u043e\u043f\u044b\u0442\u043a\u0430\u043c\u0438 \u0434\u043e\u0441\u0442\u0443\u0447\u0430\u0442\u044c\u0441\u044f \u0434\u043e Sentry.<\/p>\n<h2>\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 2. \u041e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0430 HTTP\u2011\u043e\u0448\u0438\u0431\u043e\u043a<\/h2>\n<p>\u041e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c, \u0447\u0442\u043e Sentry \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438 \u043d\u0435 \u043b\u043e\u0432\u0438\u0442 HTTP-\u043e\u0448\u0438\u0431\u043a\u0438 \u043d\u0430 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u0445 \u2014 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 404, \u0441\u043b\u043e\u043c\u0430\u043d\u043d\u044b\u0435 API-\u0432\u044b\u0437\u043e\u0432\u044b \u0438\u043b\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043f\u0440\u043e\u0445\u043e\u0434\u044f\u0442 \u043c\u0438\u043c\u043e. \u042f \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435, \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u043d\u0430 100 \u0441\u0442\u0440\u043e\u043a JS, \u043a\u043e\u0442\u043e\u0440\u043e\u0435:<\/p>\n<ul>\n<li>\n<p>\u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0447\u0435\u0440\u0435\u0437 fetch \u0438 XMLHttpRequest<\/p>\n<\/li>\n<li>\n<p>\u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0438 (\u043a\u043e\u0434\u044b 4xx, 5xx)<\/p>\n<\/li>\n<li>\n<p>\u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0432 Sentry \u0441 \u0434\u0435\u0442\u0430\u043b\u044f\u043c\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438 \u043e\u0442\u0432\u0435\u0442\u0430<\/p>\n<\/li>\n<\/ul>\n<p><strong>\u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f:<\/strong><\/p>\n<ul>\n<li>\n<p>\u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u044f \u043f\u043e URL \u0438 \u043a\u043e\u0434\u0430\u043c \u0441\u0442\u0430\u0442\u0443\u0441\u043e\u0432<\/p>\n<\/li>\n<li>\n<p>\u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 (MAX_CAPTURE_LENGTH = 1000 \u0431\u0430\u0439\u0442)<\/p>\n<\/li>\n<li>\n<p>\u0441\u0430\u043d\u0438\u0442\u0438\u0437\u0430\u0446\u0438\u044f \u043d\u0435\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u0445 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432 (cookie, authorization \u0438 \u0442.\u200a\u0434.)<\/p>\n<\/li>\n<li>\n<p>\u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 PII (\u043f\u0435\u0440\u0441\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445) \u043f\u0440\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438<\/p>\n<\/li>\n<\/ul>\n<pre><code>\/\/ sentry-http-integration.js\/** * \u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0430 HTTP-\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0430\u0445 \u0432 Sentry. * \u041e\u0441\u043d\u043e\u0432\u0430\u043d\u0430 \u043d\u0430 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 httpClientIntegration \u0438\u0437 Sentry, \u043d\u043e \u0441 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044f\u043c\u0438 * \u0434\u043b\u044f \u0431\u043e\u043b\u0435\u0435 \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0430\u043d\u0430\u043b\u0438\u0437\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438 \u043e\u0442\u0432\u0435\u0442\u043e\u0432. * * @see \u041e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u0430\u044f \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f Sentry: https:\/\/docs.sentry.io\/platforms\/javascript\/ *\/class SentryHttpDataIntegration {    \/**     * \u0423\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438.     * @type {string}     *\/    static id = 'SentryHttpDataIntegration';    \/**     * \u0418\u043c\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438.     * @type {string}     *\/    name = 'SentryHttpDataIntegration';    \/**     * \u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u0430\u044f \u0434\u043b\u0438\u043d\u0430 \u0437\u0430\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u043c\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0431\u0430\u0439\u0442\u0430\u0445.     * \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u043f\u0440\u0435\u0434\u043e\u0442\u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 Sentry.     * @type {number}     *\/    static MAX_CAPTURE_LENGTH = 1000;    \/**     * \u0421\u043f\u0438\u0441\u043e\u043a \"\u043d\u0435\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u0445\" \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432, \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430\u0445.     * @type {Array&lt;string&gt;}     * @private     *\/    static _RESTRICTED_HEADERS = [        'set-cookie',        'set-cookie2',        'cookie2',        'cookie',        'authorization',        'proxy-authorization',        'sec-',        'proxy-'    ];    \/**     * \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0434\u043b\u044f \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u0438 HTTP-\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0431\u0443\u0434\u0443\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u044f.     * @type {Object}     * @property {Array&lt;Array&lt;number&gt;|number&gt;} failedRequestStatusCodes - \u041a\u043e\u0434\u044b HTTP-\u0441\u0442\u0430\u0442\u0443\u0441\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u0447\u0438\u0442\u0430\u044e\u0442\u0441\u044f \u043e\u0448\u0438\u0431\u043a\u0430\u043c\u0438     * @property {Array&lt;string|RegExp&gt;} failedRequestTargets - URL-\u0448\u0430\u0431\u043b\u043e\u043d\u044b \u0434\u043b\u044f \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u043e\u0448\u0438\u0431\u043e\u043a     * @private     *\/    _options = {        failedRequestStatusCodes: [[500, 599]],        failedRequestTargets: [\/.*\/],    };    \/**     * \u041a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043a\u043b\u0430\u0441\u0441\u0430.     * @param {Object} options - \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438     * @param {Array&lt;Array&lt;number&gt;|number&gt;} [options.failedRequestStatusCodes] - \u041a\u043e\u0434\u044b HTTP-\u0441\u0442\u0430\u0442\u0443\u0441\u043e\u0432 \u0434\u043b\u044f \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f     * @param {Array&lt;string|RegExp&gt;} [options.failedRequestTargets] - URL-\u0448\u0430\u0431\u043b\u043e\u043d\u044b \u0434\u043b\u044f \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f     *\/    constructor(options = {}) {        this._options = {            ...this._options,            ...options,        };    }    \/**     * \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0447\u0438\u043a\u0438 \u0434\u043b\u044f fetch \u0438 XMLHttpRequest.     * \u042d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f Sentry \u043f\u0440\u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438.     *\/    setupOnce() {        this._wrapFetch();        this._wrapXHR();    }    \/**     * \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0434\u043e\u043b\u0436\u0435\u043d \u043b\u0438 \u0437\u0430\u043f\u0440\u043e\u0441 \u0431\u044b\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0435\u0433\u043e URL \u0438 \u0441\u0442\u0430\u0442\u0443\u0441\u0430 \u043e\u0442\u0432\u0435\u0442\u0430.     * @param {number} status - \u041a\u043e\u0434 HTTP-\u0441\u0442\u0430\u0442\u0443\u0441\u0430     * @param {string} url - URL \u0437\u0430\u043f\u0440\u043e\u0441\u0430     * @returns {boolean} - true, \u0435\u0441\u043b\u0438 \u0437\u0430\u043f\u0440\u043e\u0441 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043a\u0440\u0438\u0442\u0435\u0440\u0438\u044f\u043c \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0432 Sentry     * @private     *\/    _shouldCaptureResponse(status, url) {        \/\/ \u041d\u0435 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043a \u0441\u0430\u043c\u043e\u043c\u0443 Sentry        if (this._isSentryRequest(url)) {            return false;        }        return (            this._isInStatusCodeRange(status) &amp;&amp;            this._isUrlInTargets(url)        );    }    \/**     * \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043b\u0438 \u043a\u043e\u0434 \u0441\u0442\u0430\u0442\u0443\u0441\u0430 \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u043c \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d\u0430\u043c \u043e\u0448\u0438\u0431\u043e\u043a.     * @param {number} status - \u041a\u043e\u0434 HTTP-\u0441\u0442\u0430\u0442\u0443\u0441\u0430     * @returns {boolean} - true, \u0435\u0441\u043b\u0438 \u0441\u0442\u0430\u0442\u0443\u0441 \u0432\u0445\u043e\u0434\u0438\u0442 \u0432 \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d\u044b \u043e\u0448\u0438\u0431\u043e\u043a     * @private     *\/    _isInStatusCodeRange(status) {        return this._options.failedRequestStatusCodes.some(range =&gt; {            if (typeof range === 'number') {                return status === range;            }            return status &gt;= range[0] &amp;&amp; status &lt;= range[1];        });    }    \/**     * \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043b\u0438 URL \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u043c \u0448\u0430\u0431\u043b\u043e\u043d\u0430\u043c.     * @param {string} url - URL \u0437\u0430\u043f\u0440\u043e\u0441\u0430     * @returns {boolean} - true, \u0435\u0441\u043b\u0438 URL \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0445\u043e\u0442\u044f \u0431\u044b \u043e\u0434\u043d\u043e\u043c\u0443 \u0448\u0430\u0431\u043b\u043e\u043d\u0443     * @private     *\/    _isUrlInTargets(url) {        return this._options.failedRequestTargets.some(target =&gt; {            if (typeof target === 'string') {                return url.includes(target);            }            return target.test(url);        });    }    \/**     * \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043b\u0438 \u0437\u0430\u043f\u0440\u043e\u0441 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c \u043a Sentry.     * @param {string} url - URL \u0437\u0430\u043f\u0440\u043e\u0441\u0430     * @returns {boolean} - true, \u0435\u0441\u043b\u0438 \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d \u043a Sentry     * @private     *\/    _isSentryRequest(url) {        \/\/ \u041f\u0440\u043e\u0441\u0442\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043a Sentry        \/\/ \u0412 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f isSentryRequestUrl \u0438\u0437 @sentry\/core        return url.includes('sentry.io') || url.includes('ingest.sentry.io');    }    \/**     * \u041f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 fetch API \u0434\u043b\u044f \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432.     * \u0417\u0430\u043c\u0435\u043d\u044f\u0435\u0442 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e fetch \u043d\u0430 \u0441\u0432\u043e\u044e \u043e\u0431\u0435\u0440\u0442\u043a\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f:     * - \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0435     * - \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441     * - \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0438 \u0438 \u043e\u0442\u0432\u0435\u0442\u044b \u0441 \u043a\u043e\u0434\u043e\u043c \u043e\u0448\u0438\u0431\u043a\u0438 (4xx, 5xx)     * - \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0432 Sentry \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0448\u0438\u0431\u043a\u0438     * @private     *\/    _wrapFetch() {        if (typeof window.fetch !== 'function') {            console.warn('Fetch API \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u044d\u0442\u043e\u043c \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0438');            return;        }        const originalFetch = window.fetch;        const self = this;        window.fetch = async function (input, init) {            \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043c\u0435\u0442\u043e\u0434 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 (GET \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e)            const method = init?.method ?? 'GET';            \/\/ \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 Request \u0434\u043b\u044f \u0443\u043d\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u0444\u043e\u0440\u043c\u0430\u0442\u0430\u043c\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432            const request = self._getRequest(input, init);            \/\/ \u0417\u0430\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u0435\u0441\u043b\u0438 \u043e\u043d\u0438 \u0435\u0441\u0442\u044c            const requestData = init?.body                ? await self._captureRequestBody(init.body)                : null;            \/\/ \u0418\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u043c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u0435\u0441\u043b\u0438 sendDefaultPii \u0430\u043a\u0442\u0438\u0432\u0435\u043d            let requestHeaders;            if (self._shouldSendDefaultPii()) {                try {                    requestHeaders = self._extractFetchHeaders(request.headers);                    \/\/ \u0423\u0434\u0430\u043b\u044f\u0435\u043c \u043d\u0435\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438                    self._sanitizeHeaders(requestHeaders);                } catch (e) {                    \/\/ \u0418\u0433\u043d\u043e\u0440\u0438\u0440\u0443\u0435\u043c \u043e\u0448\u0438\u0431\u043a\u0438 \u043f\u0440\u0438 \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u0438 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432                }            }            try {                \/\/ \u0412\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441                const response = await originalFetch.apply(this, arguments);                \/\/ \u0415\u0441\u043b\u0438 \u043e\u0442\u0432\u0435\u0442 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043a\u0440\u0438\u0442\u0435\u0440\u0438\u044f\u043c \u043e\u0448\u0438\u0431\u043a\u0438                if (self._shouldCaptureResponse(response.status, response.url)) {                    \/\/ \u0418\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u043c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u043e\u0442\u0432\u0435\u0442\u0430, \u0435\u0441\u043b\u0438 \u0430\u043a\u0442\u0438\u0432\u0435\u043d sendDefaultPii                    let responseHeaders;                    if (self._shouldSendDefaultPii()) {                        try {                            responseHeaders = self._extractFetchHeaders(response.headers);                            \/\/ \u0423\u0434\u0430\u043b\u044f\u0435\u043c \u043d\u0435\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438                            self._sanitizeHeaders(responseHeaders);                        } catch (e) {                            \/\/ \u0418\u0433\u043d\u043e\u0440\u0438\u0440\u0443\u0435\u043c \u043e\u0448\u0438\u0431\u043a\u0438 \u043f\u0440\u0438 \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u0438 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432                        }                    }                    \/\/ \u0417\u0430\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u0442\u0435\u043b\u043e \u043e\u0442\u0432\u0435\u0442\u0430                    const responseData = await self._captureResponseBody(response.clone());                    \/\/ \u041e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435 \u0432 Sentry                    self._captureError({                        method,                        url: response.url,                        requestData,                        requestHeaders,                        responseData,                        responseHeaders,                        status: response.status                    });                }                return response;            } catch (error) {                \/\/ \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u0441\u0435\u0442\u0435\u0432\u043e\u0439 \u043e\u0448\u0438\u0431\u043a\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0432 Sentry                self._captureError({                    method,                    url: request.url,                    requestData,                    requestHeaders,                    error: error.message,                    status: ''                });                \/\/ \u041f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u043e\u0448\u0438\u0431\u043a\u0443 \u0434\u0430\u043b\u044c\u0448\u0435                throw error;            }        };    }    \/**     * \u0421\u043e\u0437\u0434\u0430\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 Request \u0438\u0437 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 fetch.     * @param {RequestInfo} input - URL \u0438\u043b\u0438 \u043e\u0431\u044a\u0435\u043a\u0442 Request     * @param {RequestInit} [init] - \u041e\u043f\u0446\u0438\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430     * @returns {Request} - \u041e\u0431\u044a\u0435\u043a\u0442 Request     * @private     *\/    _getRequest(input, init) {        if (!init &amp;&amp; input instanceof Request) {            return input;        }        \/\/ \u0415\u0441\u043b\u0438 \u0442\u0435\u043b\u043e \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e Request \u0443\u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u043e, \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0435\u0433\u043e        if (input instanceof Request &amp;&amp; input.bodyUsed) {            return input;        }        return new Request(input, init);    }    \/**     * \u041f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 XMLHttpRequest \u0434\u043b\u044f \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432.     * \u041c\u043e\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u0442 \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f XMLHttpRequest, \u0437\u0430\u043c\u0435\u043d\u044f\u044f \u043c\u0435\u0442\u043e\u0434\u044b open \u0438 send     * \u0434\u043b\u044f \u0441\u0431\u043e\u0440\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u0445 \u0438 \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0430 \u043e\u0448\u0438\u0431\u043e\u043a.     * @private     *\/    _wrapXHR() {        if (typeof XMLHttpRequest === 'undefined') {            console.warn('XMLHttpRequest \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u044d\u0442\u043e\u043c \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0438');            return;        }        const originalSend = XMLHttpRequest.prototype.send;        const originalOpen = XMLHttpRequest.prototype.open;        const self = this;        \/\/ \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u043c\u0435\u0442\u043e\u0434 \u0438 URL \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0447\u0435\u0440\u0435\u0437 \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442 open        XMLHttpRequest.prototype.open = function (method, url) {            this._method = method;            this._url = url;            this._requestHeaders = {};            return originalOpen.apply(this, arguments);        };        \/\/ \u041f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u043c setRequestHeader \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432        const originalSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader;        XMLHttpRequest.prototype.setRequestHeader = function (name, value) {            if (!this._requestHeaders) {                this._requestHeaders = {};            }            this._requestHeaders[name] = value;            return originalSetRequestHeader.apply(this, arguments);        };        \/\/ \u041f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u043c\u0435\u0442\u043e\u0434 send \u0434\u043b\u044f \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432        XMLHttpRequest.prototype.send = function (body) {            \/\/ \u0417\u0430\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430            const requestData = self._captureSyncData(body);            \/\/ \u0421\u0430\u043d\u0438\u0442\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430            let requestHeaders;            if (self._shouldSendDefaultPii() &amp;&amp; this._requestHeaders) {                requestHeaders = {...this._requestHeaders};                self._sanitizeHeaders(requestHeaders);            }            \/\/ \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430            this.addEventListener('loadend', () =&gt; {                \/\/ \u0415\u0441\u043b\u0438 \u0441\u0442\u0430\u0442\u0443\u0441 \u043e\u0442\u0432\u0435\u0442\u0430 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043d\u0430 \u043e\u0448\u0438\u0431\u043a\u0443 \u0438 URL \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043a\u0440\u0438\u0442\u0435\u0440\u0438\u044f\u043c                if (self._shouldCaptureResponse(this.status, this.responseURL ?? this._url)) {                    \/\/ \u0411\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u043e\u0442\u0432\u0435\u0442\u0430                    let responseHeaders;                    if (self._shouldSendDefaultPii()) {                        try {                            \/\/ \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432 \u043e\u0442\u0432\u0435\u0442\u0430                            responseHeaders = self._getXHRResponseHeaders(this);                            \/\/ \u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0441\u0430\u043d\u0438\u0442\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438                            self._sanitizeHeaders(responseHeaders);                        } catch (e) {                            \/\/ \u0418\u0433\u043d\u043e\u0440\u0438\u0440\u0443\u0435\u043c \u043e\u0448\u0438\u0431\u043a\u0438 \u043f\u0440\u0438 \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u0438 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432                        }                    }                    \/\/ \u0417\u0430\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u0442\u0435\u043b\u043e \u043e\u0442\u0432\u0435\u0442\u0430                    const responseData = self._captureSyncXHRResponseData(this);                    \/\/ \u041e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435 \u0432 Sentry                    self._captureError({                        method: this._method ?? 'GET',                        url: this.responseURL ?? this._url,                        requestData,                        requestHeaders,                        responseData,                        responseHeaders,                        status: this.status                    });                }            });            \/\/ \u0412\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 send            return originalSend.call(this, body);        };    }    \/**     * \u0423\u0434\u0430\u043b\u044f\u0435\u0442 \u043d\u0435\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u0438\u0437 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432.     * @param {Object} headers - \u041e\u0431\u044a\u0435\u043a\u0442 \u0441 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430\u043c\u0438     * @private     *\/    _sanitizeHeaders(headers) {        if (!headers) return;        \/\/ \u0423\u0434\u0430\u043b\u044f\u0435\u043c \u043d\u0435\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438        Object.keys(headers).forEach(key =&gt; {            const lowerKey = key.toLowerCase();            if (SentryHttpDataIntegration._RESTRICTED_HEADERS.some(                restrictedHeader =&gt; lowerKey === restrictedHeader || lowerKey.startsWith(restrictedHeader)            )) {                delete headers[key];            }        });    }    \/**     * \u0411\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e \u0437\u0430\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0442\u0435\u043b\u043e \u043e\u0442\u0432\u0435\u0442\u0430 XHR.     * @param {XMLHttpRequest} xhr - \u041e\u0431\u044a\u0435\u043a\u0442 XMLHttpRequest     * @returns {string|Object|null} - \u0417\u0430\u0445\u0432\u0430\u0447\u0435\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u0442\u0432\u0435\u0442\u0430     * @private     *\/    _captureSyncXHRResponseData(xhr) {        try {            \/\/ \u0411\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0442\u0435\u043b\u043e \u043e\u0442\u0432\u0435\u0442\u0430, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044f \u0440\u0430\u0437\u043d\u044b\u0435 \u0442\u0438\u043f\u044b \u043e\u0442\u0432\u0435\u0442\u043e\u0432            let responseData = xhr.response;            \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0442\u0438\u043f \u043e\u0442\u0432\u0435\u0442\u0430 \u0438 \u043f\u0440\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u0443\u0435\u043c            if (responseData) {                if (typeof responseData === 'object') {                    try {                        \/\/ \u0414\u043b\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u0432 \u0441\u0442\u0440\u043e\u043a\u0443 JSON                        responseData = JSON.stringify(responseData).slice(0, SentryHttpDataIntegration.MAX_CAPTURE_LENGTH);                    } catch (e) {                        \/\/ \u0415\u0441\u043b\u0438 \u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u044c, \u0432\u0435\u0440\u043d\u0435\u043c \u0442\u0438\u043f \u043e\u0431\u044a\u0435\u043a\u0442\u0430                        responseData = `[${Object.prototype.toString.call(responseData)}]`;                    }                } else if (typeof responseData === 'string') {                    \/\/ \u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0432\u0430\u0435\u043c \u0434\u043b\u0438\u043d\u0443 \u0441\u0442\u0440\u043e\u043a\u0438                    responseData = responseData.slice(0, SentryHttpDataIntegration.MAX_CAPTURE_LENGTH);                } else {                    \/\/ \u0414\u043b\u044f \u0434\u0440\u0443\u0433\u0438\u0445 \u0442\u0438\u043f\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u043c \u0438\u0445 \u0432 \u0441\u0442\u0440\u043e\u043a\u0443                    responseData = String(responseData).slice(0, SentryHttpDataIntegration.MAX_CAPTURE_LENGTH);                }            }            return responseData;        } catch (e) {            return '[unable to capture response data]';        }    }    \/**     * \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u043d\u0443\u0436\u043d\u043e \u043b\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 (PII).     * @returns {boolean} - true, \u0435\u0441\u043b\u0438 \u043d\u0443\u0436\u043d\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c PII     * @private     *\/    _shouldSendDefaultPii() {        \/\/ \u0412 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u044d\u0442\u043e \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a Sentry        \/\/ \u0417\u0434\u0435\u0441\u044c \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c true \u0434\u043b\u044f \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u0438        return true;    }    \/**     * \u0418\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u0442 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u0438\u0437 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 Headers.     * @param {Headers} headers - \u041e\u0431\u044a\u0435\u043a\u0442 Headers     * @returns {Object} - \u041e\u0431\u044a\u0435\u043a\u0442 \u0441 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430\u043c\u0438     * @private     *\/    _extractFetchHeaders(headers) {        const result = {};        if (headers instanceof Headers) {            headers.forEach((value, key) =&gt; {                \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043b\u0438 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u043d\u0435\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u043c                if (!SentryHttpDataIntegration._RESTRICTED_HEADERS.some(                    restrictedHeader =&gt; key.toLowerCase() === restrictedHeader ||                        key.toLowerCase().startsWith(restrictedHeader)                )) {                    result[key] = value;                }            });        }        return result;    }    \/**     * \u0418\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u0442 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u043e\u0442\u0432\u0435\u0442\u0430 \u0438\u0437 XMLHttpRequest.     * @param {XMLHttpRequest} xhr - \u041e\u0431\u044a\u0435\u043a\u0442 XMLHttpRequest     * @returns {Object} - \u041e\u0431\u044a\u0435\u043a\u0442 \u0441 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430\u043c\u0438     * @private     *\/    _getXHRResponseHeaders(xhr) {        const headers = xhr.getAllResponseHeaders();        const result = {};        if (!headers) {            return result;        }        headers.split('\\r\\n').forEach(line =&gt; {            if (!line) return;            const separatorIndex = line.indexOf(': ');            if (separatorIndex &gt; 0) {                const key = line.substring(0, separatorIndex);                const value = line.substring(separatorIndex + 2);                \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043b\u0438 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u043d\u0435\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u043c                if (!SentryHttpDataIntegration._RESTRICTED_HEADERS.some(                    restrictedHeader =&gt; key.toLowerCase() === restrictedHeader ||                        key.toLowerCase().startsWith(restrictedHeader)                )) {                    result[key] = value;                }            }        });        return result;    }    \/**     * \u0412\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u0437\u0430\u0445\u0432\u0430\u0442\u0430 \u0434\u0430\u043d\u043d\u044b\u0445     *\/    \/**     * \u0417\u0430\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0438 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0442\u0435\u043b\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0434\u043b\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0432 Sentry.     * \u041f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u0442\u0438\u043f\u044b \u0434\u0430\u043d\u043d\u044b\u0445: FormData, Blob, Response \u0438 \u0441\u0442\u0440\u043e\u043a\u0438.     * @param {*} body - \u0422\u0435\u043b\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430     * @returns {Promise&lt;Object|string|null&gt;} - \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430     * @private     *\/    async _captureRequestBody(body) {        try {            \/\/ \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 FormData            if (body instanceof FormData) {                return Object.fromEntries(body.entries());            }            \/\/ \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0449\u0438\u0445 \u043c\u0435\u0442\u043e\u0434 text() (Request, Response, Blob)            if (typeof body.text === 'function') {                const text = await body.text();                return text.slice(0, SentryHttpDataIntegration.MAX_CAPTURE_LENGTH);            }            \/\/ \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u0442\u0438\u043f\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445            return String(body).slice(0, SentryHttpDataIntegration.MAX_CAPTURE_LENGTH);        } catch {            \/\/ \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0432\u043d\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443            return '[unable to capture request body]';        }    }    \/**     * \u0417\u0430\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0438 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0442\u0435\u043b\u043e \u043e\u0442\u0432\u0435\u0442\u0430 \u0434\u043b\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0432 Sentry.     * @param {Response} response - \u041e\u0431\u044a\u0435\u043a\u0442 Response     * @returns {Promise&lt;string&gt;} - \u0422\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0442\u0435\u043b\u0430 \u043e\u0442\u0432\u0435\u0442\u0430     * @private     *\/    async _captureResponseBody(response) {        try {            \/\/ \u041f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0442\u0435\u043b\u043e \u043a\u0430\u043a \u0442\u0435\u043a\u0441\u0442            const text = await response.text();            return text.slice(0, SentryHttpDataIntegration.MAX_CAPTURE_LENGTH);        } catch (e) {            try {                \/\/ \u0415\u0441\u043b\u0438 \u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043a\u0430\u043a \u0442\u0435\u043a\u0441\u0442, \u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u0442\u0438\u043f\u043e\u043c \u043e\u0442\u0432\u0435\u0442\u0430                const contentType = response.headers.get('content-type');                if (contentType &amp;&amp; contentType.includes('application\/json')) {                    \/\/ \u0414\u043b\u044f JSON \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435                    const clone = response.clone();                    const json = await clone.json();                    return JSON.stringify(json).slice(0, SentryHttpDataIntegration.MAX_CAPTURE_LENGTH);                }                if (contentType &amp;&amp; contentType.includes('text\/')) {                    \/\/ \u0414\u043b\u044f \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0445 \u0444\u043e\u0440\u043c\u0430\u0442\u043e\u0432 \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u0435\u0449\u0435 \u0440\u0430\u0437 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0442\u0435\u043a\u0441\u0442                    const clone = response.clone();                    return (await clone.text()).slice(0, SentryHttpDataIntegration.MAX_CAPTURE_LENGTH);                }                \/\/ \u0414\u043b\u044f \u0431\u0438\u043d\u0430\u0440\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0442\u0438\u043f\u0435                return `[binary data: ${contentType ?? 'unknown type'}]`;            } catch {                return '[unable to capture response body]';            }        }    }    \/**     * \u0421\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e \u0437\u0430\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f XMLHttpRequest \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432.     * @param {*} data - \u0414\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u0437\u0430\u0445\u0432\u0430\u0442\u0430     * @returns {Object|string|null} - \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435     * @private     *\/    _captureSyncData(data) {        try {            if (!data) return null;            \/\/ \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 FormData            if (data instanceof FormData) {                return Object.fromEntries(data.entries());            }            \/\/ \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 Blob            if (data instanceof Blob) {                return `[Blob data: ${data.type ?? 'unknown type'}, size: ${data.size} bytes]`;            }            \/\/ \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 ArrayBuffer            if (data instanceof ArrayBuffer) {                return `[ArrayBuffer data: size: ${data.byteLength} bytes]`;            }            \/\/ \u0415\u0441\u043b\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 - \u043e\u0431\u044a\u0435\u043a\u0442, \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u044c \u0432 JSON            if (typeof data === 'object' &amp;&amp; data !== null) {                try {                    return JSON.stringify(data).slice(0, SentryHttpDataIntegration.MAX_CAPTURE_LENGTH);                } catch (e) {                    return `[object: ${Object.prototype.toString.call(data)}]`;                }            }            \/\/ \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u0442\u0438\u043f\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445            return String(data).slice(0, SentryHttpDataIntegration.MAX_CAPTURE_LENGTH);        } catch (e) {            return '[unable to capture data]';        }    }    \/**     * \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0440\u0430\u0437\u043c\u0435\u0440 \u043e\u0442\u0432\u0435\u0442\u0430 \u0438\u0437 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 Content-Length.     * @param {Object} headers - \u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u043e\u0442\u0432\u0435\u0442\u0430     * @returns {number|undefined} - \u0420\u0430\u0437\u043c\u0435\u0440 \u043e\u0442\u0432\u0435\u0442\u0430 \u0432 \u0431\u0430\u0439\u0442\u0430\u0445 \u0438\u043b\u0438 undefined     * @private     *\/    _getResponseSizeFromHeaders(headers) {        if (!headers) return undefined;        const contentLength = headers['Content-Length'] ?? headers['content-length'];        if (contentLength) {            return parseInt(contentLength, 10);        }        return undefined;    }    \/**     * \u0424\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442 \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435 \u0432 Sentry.     * @param {Object} details - \u0414\u0435\u0442\u0430\u043b\u0438 \u043e\u0448\u0438\u0431\u043a\u0438     * @param {string} details.method - HTTP \u043c\u0435\u0442\u043e\u0434 \u0437\u0430\u043f\u0440\u043e\u0441\u0430     * @param {string} details.url - URL \u0437\u0430\u043f\u0440\u043e\u0441\u0430     * @param {*} details.requestData - \u0414\u0430\u043d\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430     * @param {Object} [details.requestHeaders] - \u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430     * @param {number} [details.status] - \u0421\u0442\u0430\u0442\u0443\u0441 \u043e\u0442\u0432\u0435\u0442\u0430 (\u0435\u0441\u043b\u0438 \u0435\u0441\u0442\u044c)     * @param {*} [details.responseData] - \u0414\u0430\u043d\u043d\u044b\u0435 \u043e\u0442\u0432\u0435\u0442\u0430 (\u0435\u0441\u043b\u0438 \u0435\u0441\u0442\u044c)     * @param {Object} [details.responseHeaders] - \u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u043e\u0442\u0432\u0435\u0442\u0430     * @param {string} [details.error] - \u0421\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435 (\u0435\u0441\u043b\u0438 \u0435\u0441\u0442\u044c)     * @private     *\/    _captureError(details) {        \/\/ \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u043e\u0448\u0438\u0431\u043a\u0438 \u0441 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435\u043c \u0438\u0437 details.error \u0438\u043b\u0438 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0441\u0442\u0430\u0442\u0443\u0441\u0430 \u043e\u0442\u0432\u0435\u0442\u0430        const error = new Error(details.error ?? `HTTP Error ${details.status ?? ''}`);        \/\/ \u0424\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435        const message = `HTTP Client Error: ${details.method} ${details.url} ${details.status ?? ''}`;        \/\/ \u0424\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0434\u043b\u044f Sentry        const event = {            message,            exception: {                values: [                    {                        type: 'Error',                        value: message,                    },                ],            },            request: {                url: details.url,                method: details.method,                headers: details.requestHeaders,                data: details.requestData,            },            contexts: {                response: {                    status_code: details.status,                    headers: details.responseHeaders ?? {},                    data: details.responseData ?? {},                    body_size: this._getResponseSizeFromHeaders(details.responseHeaders),                },            },        };        \/\/ \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f        this._addExceptionMechanism(event);        \/\/ \u041e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0432 Sentry        Sentry.captureException(error, {            contexts: event.contexts,            request: event.request,            tags: {                'http.status_code': details.status ?? '',                'http.method': details.method,            },        });    }    \/**     * \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a \u0441\u043e\u0431\u044b\u0442\u0438\u044e.     * @param {Object} event - \u0421\u043e\u0431\u044b\u0442\u0438\u0435 Sentry     * @private     *\/    _addExceptionMechanism(event) {        if (event.exception &amp;&amp; event.exception.values &amp;&amp; event.exception.values[0]) {            event.exception.values[0].mechanism = {                type: 'http.client',                handled: false,            };        }    }}\/** * \u0423\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 \u044d\u043a\u0441\u043f\u043e\u0440\u0442 \u043a\u043b\u0430\u0441\u0441\u0430 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438. * \u041f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043a\u0430\u043a CommonJS \u043c\u043e\u0434\u0443\u043b\u0438 (Node.js), \u0442\u0430\u043a \u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u0443\u044e \u0441\u0440\u0435\u0434\u0443. *\/if (typeof module !== 'undefined' &amp;&amp; module.exports) {    module.exports = SentryHttpDataIntegration;} else {    window.SentryHttpDataIntegration = SentryHttpDataIntegration;}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h2>\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 3. \u0411\u044b\u0441\u0442\u0440\u043e\u0435 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0434\u0438\u0441\u043a\u0430<\/h2>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u2014 \u0431\u044b\u0441\u0442\u0440\u043e\u0435 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0434\u0438\u0441\u043a\u0430. 40 \u0413\u0411 \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u043b\u0438\u0441\u044c \u0437\u0430 \u0447\u0430\u0441\u044b \u043f\u0440\u0438 \u0432\u043a\u043b\u044e\u0447\u0451\u043d\u043d\u043e\u043c \u0442\u0440\u0435\u0439\u0441\u0438\u043d\u0433\u0435 \u0438 \u043c\u0435\u0442\u0440\u0438\u043a\u0430\u0445. Sentry \u043d\u0430\u043a\u0430\u043f\u043b\u0438\u0432\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 ClickHouse, Kafka \u0438 Postgres.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u0441\u0451-\u0442\u0430\u043a\u0438 Sentry \u0437\u0430\u043f\u043e\u043b\u043d\u0438\u043b \u0432\u0441\u0451 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e, \u043d\u043e \u043f\u043e\u0432\u044b\u0448\u0430\u0442\u044c \u043e\u0431\u044a\u0451\u043c \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 \u0432\u044b \u043d\u0435 \u0445\u043e\u0442\u0438\u0442\u0435, \u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 docker-volume. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, sentry-kafka, sentry-seaweedfs, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u0430\u0436\u0435 sentry-data. \u041f\u043e\u0441\u043b\u0435 \u0438\u0445 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435 \u0441\u043a\u0440\u0438\u043f\u0442 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 Sentry, \u0438 \u043e\u043d \u0437\u0430\u043d\u043e\u0432\u043e \u0441\u043e\u0437\u0434\u0430\u0441\u0442 \u043d\u0443\u0436\u043d\u044b\u0435 docker volume.\u00a0<\/p>\n<p><strong>\u0420\u0435\u0448\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0441\u043d\u0438\u0436\u0435\u043d\u0438\u044f \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0438:<\/strong><\/p>\n<ol>\n<li>\n<p><strong>\u0421\u043d\u0438\u0436\u0435\u043d\u0438\u0435 \u0441\u0440\u043e\u043a\u0430 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u0439.<\/strong> \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438 \u0441\u0440\u043e\u043a \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 \u0434\u043e 2-4 \u0434\u043d\u0435\u0439 (\u0432 \u0444\u0430\u0439\u043b\u0435 .env: SENTRY_EVENT_RETENTION_DAYS). \u0414\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f 14 \u0434\u043d\u0435\u0439 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f 200+ \u0413\u0411.<\/p>\n<\/li>\n<li>\n<p><strong>\u041e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043d\u0435\u043d\u0443\u0436\u043d\u044b\u0445 \u0442\u0440\u0435\u0439\u0441\u0438\u043d\u0433\u043e\u0432:<\/strong><\/p>\n<ul>\n<li>\n<p>\u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u044b\u0435 \u0441\u043f\u0430\u043d\u044b<\/p>\n<\/li>\n<li>\n<p>\u043e\u0448\u0438\u0431\u043a\u0438 \u043e\u0442 \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 CDN (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0442\u0430\u0439\u043c\u0430\u0443\u0442\u044b Google Fonts)<\/p>\n<\/li>\n<li>\n<p>\u0444\u043e\u043d\u043e\u0432\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 (\u0432\u043a\u043b\u0430\u0434\u043a\u0430 Performance \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430)<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<p>3. <strong>\u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f Kafka:<\/strong><\/p>\n<ul>\n<li>\n<p>\u0443\u043c\u0435\u043d\u044c\u0448\u0438\u043b\u0438 retention \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0434\u043e \u043c\u0438\u043d\u0438\u043c\u0443\u043c\u0430 \u2014 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0438 \u0443\u0434\u0430\u043b\u044f\u044e\u0442\u0441\u044f.<\/p>\n<\/li>\n<\/ul>\n<p>\u0422\u0430\u043a\u0438\u0435 \u0443 \u043d\u0430\u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0434\u043b\u044f \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 Kafka:\u00a0<\/p>\n<p>KAFKA_LOG_RETENTION_HOURS: &#171;1&#187;<\/p>\n<p>KAFKA_MESSAGE_MAX_BYTES: &#171;10000000&#187; #10MB or bust<\/p>\n<p>KAFKA_MAX_REQUEST_SIZE: &#171;10000000&#187; #10MB on requests apparently too<\/p>\n<p>CONFLUENT_SUPPORT_METRICS_ENABLE: &#171;false&#187;<\/p>\n<p>KAFKA_LOG_RETENTION_BYTES: &#171;10737418240&#187; # 10 GiB (server default; \u043f\u043e\u043c\u043d\u0438\u0442\u0435 \u043f\u0440\u043e &#171;\u043d\u0430 \u043f\u0430\u0440\u0442\u0438\u0446\u0438\u044e&#187;)<\/p>\n<p>KAFKA_LOG_SEGMENT_BYTES: &#171;268435456&#187; # 256 MiB \u0441\u0435\u0433\u043c\u0435\u043d\u0442, \u0447\u0442\u043e\u0431\u044b \u0431\u044b\u0441\u0442\u0440\u0435\u0435 \u0437\u0430\u043a\u0440\u044b\u0432\u0430\u043b\u0438\u0441\u044c \u0438 \u0443\u0434\u0430\u043b\u044f\u043b\u0438\u0441\u044c<\/p>\n<p>KAFKA_LOG_RETENTION_CHECK_INTERVAL_MS: &#171;300000&#187; # \u043a\u0430\u0436\u0434\u044b\u0435 5 \u043c\u0438\u043d\u0443\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c old segments<\/p>\n<p>KAFKA_LOG_SEGMENT_DELETE_DELAY_MS: &#171;60000&#187; # \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0430 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u0430<\/p>\n<p>KAFKA_LOG_CLEANUP_POLICY: &#171;delete&#187;<\/p>\n<p>KAFKA_LOG_CLEANER_ENABLE: true<\/p>\n<p>\u0412\u043e\u0442 \u0435\u0449\u0451 \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0434\u043e\u043a\u0443: <a href=\"https:\/\/develop.sentry.dev\/self-hosted\/troubleshooting\/kafka\/#reducing-disk-usage\" rel=\"noopener noreferrer nofollow\">https:\/\/develop.sentry.dev\/self-hosted\/troubleshooting\/kafka\/#reducing-disk-usage<\/a><\/p>\n<ol start=\"3\">\n<li>\n<p>\u0412\u0440\u0443\u0447\u043d\u0443\u044e \u0447\u0438\u0441\u0442\u0438\u043b\u0438 ClickHouse: TRUNCATE \u043d\u0430 \u0441\u0442\u0430\u0440\u044b\u0445 \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u0445 \u0432\u0440\u043e\u0434\u0435 spans_local, transactions_local.\u00a0<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0441\u0442\u0440\u043e\u0438\u043b\u0438 cron \u0434\u043b\u044f \u0435\u0436\u0435\u0434\u043d\u0435\u0432\u043d\u043e\u0439 \u043e\u0447\u0438\u0441\u0442\u043a\u0438 \u0444\u0430\u0439\u043b\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0430\u0448\u0435\u0433\u043e \u0441\u0440\u043e\u043a\u0430 \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0435: find \/var\/lib\/docker\/volumes\/sentry-data\/_data -type f -mtime +3 -delete<\/p>\n<\/li>\n<\/ol>\n<p><strong>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u00a0<\/strong><\/p>\n<p>\u0420\u0430\u0437\u0432\u0451\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u0435 Sentry self\u2011hosted \u2014 \u0437\u0430\u0434\u0430\u0447\u0430 \u043d\u0435\u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u0430\u044f, \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0434\u043b\u044f \u0432\u044b\u0441\u043e\u043a\u043e\u043d\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432. \u0412 \u0445\u043e\u0434\u0435 \u0440\u0430\u0431\u043e\u0442\u044b \u043c\u044b:<\/p>\n<ul>\n<li>\n<p>\u0443\u0441\u0442\u0440\u0430\u043d\u0438\u043b\u0438 \u0437\u0430\u0432\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0430\u0439\u0442\u0430 \u0438\u0437\u2011\u0437\u0430 \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0441\u0442\u0438 Sentry (\u043b\u043e\u043a\u0430\u043b\u044c\u043d\u0430\u044f JS\u2011\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 + \u0442\u0430\u0439\u043c\u0430\u0443\u0442\u044b);<\/p>\n<\/li>\n<li>\n<p>\u0440\u0430\u0441\u0448\u0438\u0440\u0438\u043b\u0438 \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433 \u043e\u0448\u0438\u0431\u043e\u043a (\u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0430 HTTP\u2011\u043e\u0448\u0438\u0431\u043e\u043a);<\/p>\n<\/li>\n<li>\n<p>\u0441\u043d\u0438\u0437\u0438\u043b\u0438 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u043d\u0430 \u0434\u0438\u0441\u043a (\u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f Kafka, ClickHouse, \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 retention).<\/p>\n<\/li>\n<\/ul>\n<p><strong>\u0420\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u0442\u0435\u0445, \u043a\u0442\u043e \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u0435\u0442 \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c Sentry self\u2011hosted:<\/strong><\/p>\n<ol>\n<li>\n<p>\u041d\u0430\u0447\u0438\u043d\u0430\u0439\u0442\u0435 \u0441 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0435 (\u043c\u0438\u043d\u0438\u043c\u0443\u043c 16 \u0413\u0411 RAM, 4 \u044f\u0434\u0440\u0430 CPU).<\/p>\n<\/li>\n<li>\n<p>\u0421\u0440\u0430\u0437\u0443 \u043b\u043e\u043a\u0430\u043b\u0438\u0437\u0443\u0439\u0442\u0435 JS\u2011\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 Sentry \u2014 \u044d\u0442\u043e \u043f\u0440\u0435\u0434\u043e\u0442\u0432\u0440\u0430\u0442\u0438\u0442 \u0437\u0430\u0432\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0430\u0439\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u0442\u0435 \u0442\u0430\u0439\u043c\u0430\u0443\u0442\u044b \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043a Sentry \u2014 300\u2013500 \u043c\u0441 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0434\u043b\u044f \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0430 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u0432.<\/p>\n<\/li>\n<li>\n<p>\u041e\u0442\u043a\u043b\u044e\u0447\u0430\u0439\u0442\u0435 \u043d\u0435\u043d\u0443\u0436\u043d\u044b\u0435 \u0442\u0440\u0435\u0439\u0441\u0438\u043d\u0433\u0438 \u0438 \u043c\u0435\u0442\u0440\u0438\u043a\u0438 \u2014 \u044d\u0442\u043e \u0441\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0442 \u043c\u0435\u0441\u0442\u043e \u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u044b.<\/p>\n<\/li>\n<li>\n<p>\u0420\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0439\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0434\u0438\u0441\u043a\u0430 \u0438 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0439\u0442\u0435 retention \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<\/li>\n<li>\n<p>\u0422\u0435\u0441\u0442\u0438\u0440\u0443\u0439\u0442\u0435 \u043e\u0442\u043a\u0430\u0437\u043e\u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u043e\u0441\u0442\u044c \u2014 \u0441\u0438\u043c\u0443\u043b\u0438\u0440\u0443\u0439\u0442\u0435 \u0441\u0431\u043e\u0438 Sentry \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0439\u0442\u0435 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<\/li>\n<\/ol>\n<p>\u0415\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u043e\u0441\u0442\u0430\u043b\u0438\u0441\u044c \u0432\u043e\u043f\u0440\u043e\u0441\u044b \u0438\u043b\u0438 \u0435\u0441\u0442\u044c \u0438\u0434\u0435\u0438 \u0434\u043b\u044f \u0443\u043b\u0443\u0447\u0448\u0435\u043d\u0438\u044f \u2014 \u043f\u0438\u0448\u0438\u0442\u0435 \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445!\u00a0<\/p>\n<\/div>\n<p>\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/1030358\/\">https:\/\/habr.com\/ru\/articles\/1030358\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u041f\u0440\u0438\u0432\u0435\u0442! \u041c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u0414\u0430\u043d\u0438\u0438\u043b \u0422\u043a\u0430\u0447\u0435\u043d\u043a\u043e, \u044f \u0432\u0435\u0431\u2011\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0432 \u0418\u0422\u2011\u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438 \u00ab\u0410\u043a\u0442\u0438\u0432\u0438\u043a\u0430\u00bb. \u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043f\u043e\u0434\u0435\u043b\u044e\u0441\u044c \u043e\u043f\u044b\u0442\u043e\u043c \u0440\u0430\u0437\u0432\u0451\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f Sentry self\u2011hosted \u0434\u043b\u044f \u0432\u044b\u0441\u043e\u043a\u043e\u043d\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u043e\u0431\u0438\u043b\u0438\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u043e\u0432 \u043f\u043e SaaS\u2011\u0432\u0435\u0440\u0441\u0438\u0438, \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0445 \u0433\u0430\u0439\u0434\u043e\u0432 \u043f\u043e self\u2011hosted\u2011\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0435 \u043f\u043e\u0447\u0442\u0438 \u043d\u0435\u0442 \u2014 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0441 \u0443\u0447\u0451\u0442\u043e\u043c \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439 \u043a \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0438 \u043e\u0442\u043a\u0430\u0437\u043e\u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u043e\u0441\u0442\u0438.\u041c\u044b \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u043b\u0438\u0441\u044c \u0441 \u0440\u044f\u0434\u043e\u043c \u043f\u0440\u043e\u0431\u043b\u0435\u043c: \u043d\u0435\u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u044c\u044e \u043d\u0430 \u0431\u0430\u0437\u043e\u0432\u043e\u043c \u0445\u043e\u0441\u0442\u0438\u043d\u0433\u0435, \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435\u043c \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0430 HTTP\u2011\u043e\u0448\u0438\u0431\u043e\u043a \u0438 \u0431\u044b\u0441\u0442\u0440\u044b\u043c \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435\u043c \u0434\u0438\u0441\u043a\u0430. \u041f\u043e\u0434 \u043a\u0430\u0442\u043e\u043c \u0440\u0430\u0437\u0431\u0435\u0440\u0443 \u043a\u0430\u0436\u0434\u0443\u044e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443, \u043f\u043e\u043a\u0430\u0436\u0443 \u043a\u043e\u0434 \u0440\u0435\u0448\u0435\u043d\u0438\u0439 \u0438 \u0434\u0430\u043c \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u0442\u0435\u0445, \u043a\u0442\u043e \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u0435\u0442 \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c Sentry \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e.\u0421\u0442\u0430\u0442\u044c\u044f \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0435\u0437\u043d\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c \u0438 DevOps\u2011\u0438\u043d\u0436\u0435\u043d\u0435\u0440\u0430\u043c \u0431\u0435\u0437 \u043e\u043f\u044b\u0442\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 self\u2011hosted Sentry.\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 1. \u041d\u0435\u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043d\u0430 \u0431\u0430\u0437\u043e\u0432\u043e\u043c \u0445\u043e\u0441\u0442\u0438\u043d\u0433\u0435\u0412\u0441\u0451 \u043d\u0430\u0447\u0430\u043b\u043e\u0441\u044c \u0441 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043d\u0430 \u043d\u0430\u0448\u0435\u043c \u0431\u0430\u0437\u043e\u0432\u043e\u043c \u0445\u043e\u0441\u0442\u0438\u043d\u0433\u0435 \u0432\u043e\u0437\u043d\u0438\u043a\u043b\u0438 \u043e\u0448\u0438\u0431\u043a\u0438: Sentry \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e \u043d\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u043b\u0441\u044f \u0438\u0437\u2011\u0437\u0430 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0435\u0439 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438. \u041d\u0435\u043b\u044c\u0437\u044f \u0431\u044b\u043b\u043e \u0434\u0430\u0436\u0435 \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u044b \u043f\u0435\u0440\u0435\u0435\u0445\u0430\u043b\u0438 \u043d\u0430 \u0434\u0440\u0443\u0433\u043e\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u2014 \u0438 \u0442\u043e\u0433\u0434\u0430 \u0432\u0441\u0451 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c.\u041d\u043e \u0442\u0443\u0442 \u043c\u0435\u043d\u044f \u0442\u043e\u0436\u0435 \u043f\u043e\u0434\u0436\u0438\u0434\u0430\u043b\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b: \u043f\u0430\u043c\u044f\u0442\u044c \u0431\u044b\u0441\u0442\u0440\u043e \u0437\u0430\u0431\u0438\u0432\u0430\u043b\u0430\u0441\u044c, \u0438 \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043b\u043e\u0433\u0430\u043c\u0438 \u0432 \u0442\u043e\u043c \u0436\u0435 ClickHouse \u0438\u043b\u0438 \u0444\u0430\u0439\u043b\u0430\u043c\u0438 \u0440\u0435\u043f\u043b\u0435\u0435\u0432, \u0430 \u043b\u043e\u0433\u0430\u043c\u0438 \u0432 Kafka.\u0417\u0430 \u0432\u0440\u0435\u043c\u044f \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439 \u043a \u0434\u0435\u043c\u043e\u0432\u0435\u0440\u0441\u0438\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 (\u0430 \u0435\u0439 \u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d\u043e\u0435 \u0447\u0438\u0441\u043b\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u043e\u0432\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439) Sentry \u043f\u0430\u0434\u0430\u043b \u0434\u0432\u0430 \u0440\u0430\u0437\u0430, \u0430 \u0434\u0435\u043c\u043e-\u0432\u0435\u0440\u0441\u0438\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0433\u0440\u0443\u0437\u0438\u043b\u0430\u0441\u044c \u043e\u0447\u0435\u043d\u044c \u0434\u043e\u043b\u0433\u043e.\u00a0\u041a\u043e\u0433\u0434\u0430 Sentry \u043f\u0430\u0434\u0430\u043b, \u0441\u0430\u0439\u0442 \u0433\u0440\u0443\u0437\u0438\u043b\u0441\u044f \u043e\u0447\u0435\u043d\u044c \u0434\u043e\u043b\u0433\u043e \u2014 \u043e\u043a\u043e\u043b\u043e 30\u201340 \u0441\u0435\u043a\u0443\u043d\u0434. \u042d\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u043b\u043e \u043f\u043e\u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u043a\u043b\u0438\u0435\u043d\u0442 \u043f\u044b\u0442\u0430\u043b\u0441\u044f \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c JS\u2011\u0441\u043a\u0440\u0438\u043f\u0442\u044b \u0441 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 CDN, \u043d\u043e \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 Sentry. \u0417\u0430\u043f\u0440\u043e\u0441\u044b \u0437\u0430\u0432\u0438\u0441\u0430\u043b\u0438 \u043d\u0430 \u0442\u0430\u0439\u043c\u0430\u0443\u0442\u0430\u0445, \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b.\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438: 32 \u0413\u0411 RAM, 4 \u044f\u0434\u0440\u0430 CPU, 40 \u0413\u0411 SSD. \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438 \u0434\u043e \u0430\u0436\u0438\u043e\u0442\u0430\u0436\u0430 \u0441 \u0446\u0435\u043d\u0430\u043c\u0438 \u043d\u0430 \u043f\u0430\u043c\u044f\u0442\u044c \u2014 \u043f\u043e\u0442\u043e\u043c \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0443\u043c\u0435\u043d\u044c\u0448\u0438\u0442\u044c RAM \u0434\u043e 16-24 \u0413\u0411, \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0442\u044c SSD \u0434\u043e 100\u0413\u0411 \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c swap-\u0444\u0430\u0439\u043b, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u0435\u0440\u0435\u043f\u043b\u0430\u0447\u0438\u0432\u0430\u0442\u044c.\u00a0\u041b\u0430\u0439\u0444\u0445\u0430\u043a\u0438 \u0434\u043b\u044f \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0441\u0430\u0439\u0442\u0430, \u043a\u043e\u0433\u0434\u0430 \u0441\u0435\u043d\u0442\u0440\u0438 \u043d\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d\u0414\u0430\u0436\u0435 \u043f\u0440\u0438 self\u2011hosted \u0440\u0435\u0448\u0435\u043d\u0438\u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b \u0441\u0431\u043e\u0438: DDoS\u2011\u0430\u0442\u0430\u043a\u0438, \u043f\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0430, \u043e\u0448\u0438\u0431\u043a\u0438 \u041f\u041e. \u0414\u0435\u043b\u044e\u0441\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u0435\u043d\u043d\u044b\u043c\u0438 \u043c\u043d\u043e\u0439 \u0441\u043f\u043e\u0441\u043e\u0431\u0430\u043c\u0438 \u043c\u0438\u043d\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u0432\u043b\u0438\u044f\u043d\u0438\u0435, \u0447\u0442\u043e\u0431\u044b \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u0434\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u0430\u0439\u0442\u0430, \u0434\u0430\u0436\u0435 \u043f\u0440\u0438 \u043f\u043e\u043b\u043d\u043e\u043c \u043e\u0442\u043a\u0430\u0437\u0435 Sentry.\u0425\u0430\u043a 1. \u041b\u043e\u043a\u0430\u043b\u044c\u043d\u0430\u044f \u0443\u0440\u0435\u0437\u0430\u043d\u043d\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f JS\u2011\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438\u042f \u0441\u043a\u0430\u0447\u0430\u043b JS-\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 Sentry \u0438 \u0445\u0440\u0430\u043d\u0438\u043b \u0435\u0451 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e \u0432 \u0443\u0440\u0435\u0437\u0430\u043d\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438. \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u2014 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u0430\u044f \u0438 \u0431\u0435\u0437 \u0437\u0430\u0432\u0438\u0441\u0430\u043d\u0438\u0439.\u0425\u0430\u043a 2. \u00a0\u0422\u0430\u0439\u043c\u0430\u0443\u0442\u044b \u043d\u0430 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043a\u043e\u0434 \u0441 \u0442\u0430\u0439\u043c\u0430\u0443\u0442\u0430\u043c\u0438 \u043d\u0430 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u043f\u043e\u0432\u0435\u0440\u0445 SDK, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0440\u044b\u0432\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043a Sentry, \u0435\u0441\u043b\u0438 \u043e\u043d\u0438 \u0434\u043b\u044f\u0442\u0441\u044f \u0434\u043e\u043b\u044c\u0448\u0435 300 \u043c\u0438\u043b\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434.\u042d\u0442\u043e \u043f\u0440\u0435\u0434\u043e\u0442\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043f\u0435\u0440\u0435\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043e\u0447\u0435\u0440\u0435\u0434\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u043e\u0442\u0437\u044b\u0432\u0447\u0438\u0432\u043e\u0441\u0442\u044c \u0441\u0430\u0439\u0442\u0430.     const SENTRY_TIMEOUT_MS = 300;        function makeCustomTimeoutTransport(options) {            \/\/ The &#8216;makeRequest&#8217; function is the core where you control the fetch call.            function makeRequest(request) {                const controller = new AbortController();                const timeoutId = setTimeout(() =&gt; controller.abort(), SENTRY_TIMEOUT_MS); \/\/ 3-second timeout                const requestOptions = {                    body: request.body,                    method: &#8216;POST&#8217;,                    referrerPolicy: &#8216;origin&#8217;,                    headers: options.headers,                    signal: controller.signal, \/\/ &lt;&#8212; Connect the AbortController                    &#8230;options.fetchOptions,                };                \/\/ Return the fetch promise. It will be rejected if it times out.                return fetch(options.url, requestOptions)                    .then(response =&gt; {                        clearTimeout(timeoutId); \/\/ Clear timer on success                        return {                            statusCode: response.status,                            headers: {                                &#8216;x-sentry-rate-limits&#8217;: response.headers.get(&#8216;X-Sentry-Rate-Limits&#8217;),                                &#8216;retry-after&#8217;: response.headers.get(&#8216;Retry-After&#8217;),                            },                        };                    })                    .catch(error =&gt; {                        clearTimeout(timeoutId);                        if (error.name === &#8216;AbortError&#8217;) {                            console.warn(&#8216;Sentry event dropped due to send timeout.&#8217;);                            error.message = &#8216;Sentry event dropped due to send timeout.&#8217;;                        }                        throw error; \/\/ Re-throw to let the SDK handle the failure                    });            }            \/\/ Use the official helper to build a compliant transport.            return Sentry.createTransport(options, makeRequest);        }        Sentry.init({            transport: makeCustomTimeoutTransport,\u2026        });\u042d\u0442\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043c\u044b \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043b\u0438 \u043d\u0430 \u043f\u0440\u043e\u0434\u0435.\u00a0\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442: \u043f\u043e\u0441\u043b\u0435 \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044f \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043b\u043e \u0437\u0430\u0431\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u043b\u043e\u0433 \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u044b\u043c\u0438 \u043f\u043e\u043f\u044b\u0442\u043a\u0430\u043c\u0438 \u0434\u043e\u0441\u0442\u0443\u0447\u0430\u0442\u044c\u0441\u044f \u0434\u043e Sentry.\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 2. \u041e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0430 HTTP\u2011\u043e\u0448\u0438\u0431\u043e\u043a\u041e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c, \u0447\u0442\u043e Sentry \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438 \u043d\u0435 \u043b\u043e\u0432\u0438\u0442 HTTP-\u043e\u0448\u0438\u0431\u043a\u0438 \u043d\u0430 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u0445 \u2014 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 404, \u0441\u043b\u043e\u043c\u0430\u043d\u043d\u044b\u0435 API-\u0432\u044b\u0437\u043e\u0432\u044b \u0438\u043b\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043f\u0440\u043e\u0445\u043e\u0434\u044f\u0442 \u043c\u0438\u043c\u043e. \u042f \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435, \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u043d\u0430 100 \u0441\u0442\u0440\u043e\u043a JS, \u043a\u043e\u0442\u043e\u0440\u043e\u0435:\u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0447\u0435\u0440\u0435\u0437 fetch \u0438 XMLHttpRequest\u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0438 (\u043a\u043e\u0434\u044b 4xx, 5xx)\u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0432 Sentry \u0441 \u0434\u0435\u0442\u0430\u043b\u044f\u043c\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438 \u043e\u0442\u0432\u0435\u0442\u0430\u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f:\u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u044f \u043f\u043e URL \u0438 \u043a\u043e\u0434\u0430\u043c \u0441\u0442\u0430\u0442\u0443\u0441\u043e\u0432\u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 (MAX_CAPTURE_LENGTH = 1000 \u0431\u0430\u0439\u0442)\u0441\u0430\u043d\u0438\u0442\u0438\u0437\u0430\u0446\u0438\u044f \u043d\u0435\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u0445 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432 (cookie, authorization \u0438 \u0442.\u200a\u0434.)\u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 PII (\u043f\u0435\u0440\u0441\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445) \u043f\u0440\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438\/\/ sentry-http-integration.js\/** * \u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0430 HTTP-\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0430\u0445 \u0432 Sentry. * \u041e\u0441\u043d\u043e\u0432\u0430\u043d\u0430 \u043d\u0430 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 httpClientIntegration \u0438\u0437 Sentry, \u043d\u043e \u0441 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044f\u043c\u0438 * \u0434\u043b\u044f \u0431\u043e\u043b\u0435\u0435 \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0430\u043d\u0430\u043b\u0438\u0437\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438 \u043e\u0442\u0432\u0435\u0442\u043e\u0432. * * @see \u041e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u0430\u044f \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f Sentry: https:\/\/docs.sentry.io\/platforms\/javascript\/ *\/class SentryHttpDataIntegration {    \/**     * \u0423\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438.     * @type {string}     *\/    static id = &#8216;SentryHttpDataIntegration&#8217;;    \/**     * \u0418\u043c\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438.     * @type {string}     *\/    name = &#8216;SentryHttpDataIntegration&#8217;;    \/**     * \u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u0430\u044f \u0434\u043b\u0438\u043d\u0430 \u0437\u0430\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u043c\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0431\u0430\u0439\u0442\u0430\u0445.     * \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u043f\u0440\u0435\u0434\u043e\u0442\u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 Sentry.     * @type {number}     *\/    static MAX_CAPTURE_LENGTH = 1000;    \/**     * \u0421\u043f\u0438\u0441\u043e\u043a &#171;\u043d\u0435\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u0445&#187; \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432, \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430\u0445.     * @type {Array&lt;string&gt;}     * @private     *\/    static _RESTRICTED_HEADERS = [        &#8216;set-cookie&#8217;,        &#8216;set-cookie2&#8217;,        &#8216;cookie2&#8217;,        &#8216;cookie&#8217;,        &#8216;authorization&#8217;,        &#8216;proxy-authorization&#8217;,        &#8216;sec-&#8216;,        &#8216;proxy-&#8216;    ];    \/**     * \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0434\u043b\u044f \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u0438 HTTP-\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0431\u0443\u0434\u0443\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u044f.     * @type {Object}     * @property {Array&lt;Array&lt;number&gt;|number&gt;} failedRequestStatusCodes &#8212; \u041a\u043e\u0434\u044b HTTP-\u0441\u0442\u0430\u0442\u0443\u0441\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u0447\u0438\u0442\u0430\u044e\u0442\u0441\u044f \u043e\u0448\u0438\u0431\u043a\u0430\u043c\u0438     * @property {Array&lt;string|RegExp&gt;} failedRequestTargets &#8212; URL-\u0448\u0430\u0431\u043b\u043e\u043d\u044b \u0434\u043b\u044f \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u043e\u0448\u0438\u0431\u043e\u043a     * @private     *\/    _options = {        failedRequestStatusCodes: [[500, 599]],        failedRequestTargets: [\/.*\/],    };    \/**     * \u041a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043a\u043b\u0430\u0441\u0441\u0430.     * @param {Object} options &#8212; \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438     * @param {Array&lt;Array&lt;number&gt;|number&gt;} [options.failedRequestStatusCodes] &#8212; \u041a\u043e\u0434\u044b HTTP-\u0441\u0442\u0430\u0442\u0443\u0441\u043e\u0432 \u0434\u043b\u044f \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f     * @param {Array&lt;string|RegExp&gt;} [options.failedRequestTargets] &#8212; URL-\u0448\u0430\u0431\u043b\u043e\u043d\u044b \u0434\u043b\u044f \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f     *\/    constructor(options = {}) {        this._options = {            &#8230;this._options,            &#8230;options,        };    }    \/**     * \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0447\u0438\u043a\u0438 \u0434\u043b\u044f fetch \u0438 XMLHttpRequest.     * \u042d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f Sentry \u043f\u0440\u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438.     *\/    setupOnce() {        this._wrapFetch();        this._wrapXHR();    }    \/**     * \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0434\u043e\u043b\u0436\u0435\u043d \u043b\u0438 \u0437\u0430\u043f\u0440\u043e\u0441 \u0431\u044b\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0435\u0433\u043e URL \u0438 \u0441\u0442\u0430\u0442\u0443\u0441\u0430 \u043e\u0442\u0432\u0435\u0442\u0430.     * @param {number} status &#8212; \u041a\u043e\u0434 HTTP-\u0441\u0442\u0430\u0442\u0443\u0441\u0430     * @param {string} url &#8212; URL \u0437\u0430\u043f\u0440\u043e\u0441\u0430     * @returns {boolean} &#8212; true, \u0435\u0441\u043b\u0438 \u0437\u0430\u043f\u0440\u043e\u0441 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043a\u0440\u0438\u0442\u0435\u0440\u0438\u044f\u043c \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0432 Sentry     * @private     *\/    _shouldCaptureResponse(status, url) {        \/\/ \u041d\u0435 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043a \u0441\u0430\u043c\u043e\u043c\u0443 Sentry        if (this._isSentryRequest(url)) {            return false;        }        return (            this._isInStatusCodeRange(status) &amp;&amp;            this._isUrlInTargets(url)        );    }    \/**     * \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043b\u0438 \u043a\u043e\u0434 \u0441\u0442\u0430\u0442\u0443\u0441\u0430 \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u043c \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d\u0430\u043c \u043e\u0448\u0438\u0431\u043e\u043a.     * @param {number} status &#8212; \u041a\u043e\u0434 HTTP-\u0441\u0442\u0430\u0442\u0443\u0441\u0430     * @returns {boolean} &#8212; true, \u0435\u0441\u043b\u0438 \u0441\u0442\u0430\u0442\u0443\u0441 \u0432\u0445\u043e\u0434\u0438\u0442 \u0432 \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d\u044b \u043e\u0448\u0438\u0431\u043e\u043a     * @private     *\/    _isInStatusCodeRange(status) {        return this._options.failedRequestStatusCodes.some(range =&gt; {            if (typeof range === &#8216;number&#8217;) {                return status === range;            }            return status &gt;= range[0] &amp;&amp; status &lt;= range[1];        });    }    \/**     * \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043b\u0438 URL \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u043c \u0448\u0430\u0431\u043b\u043e\u043d\u0430\u043c.     * @param {string} url &#8212; URL \u0437\u0430\u043f\u0440\u043e\u0441\u0430     * @returns {boolean} &#8212; true, \u0435\u0441\u043b\u0438 URL \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0445\u043e\u0442\u044f \u0431\u044b \u043e\u0434\u043d\u043e\u043c\u0443 \u0448\u0430\u0431\u043b\u043e\u043d\u0443     * @private     *\/    _isUrlInTargets(url) {        return this._options.failedRequestTargets.some(target =&gt; {            if (typeof target === &#8216;string&#8217;) {                return url.includes(target);            }            return target.test(url);        });    }    \/**     * \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043b\u0438 \u0437\u0430\u043f\u0440\u043e\u0441 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c \u043a Sentry.     * @param {string} url &#8212; URL \u0437\u0430\u043f\u0440\u043e\u0441\u0430     * @returns {boolean} &#8212; true, \u0435\u0441\u043b\u0438 \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d \u043a Sentry     * @private     *\/    _isSentryRequest(url) {        \/\/ \u041f\u0440\u043e\u0441\u0442\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043a Sentry        \/\/ \u0412 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f isSentryRequestUrl \u0438\u0437 @sentry\/core        return url.includes(&#8216;sentry.io&#8217;) || url.includes(&#8216;ingest.sentry.io&#8217;);    }    \/**     * \u041f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 fetch API \u0434\u043b\u044f \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432.     * \u0417\u0430\u043c\u0435\u043d\u044f\u0435\u0442 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e fetch \u043d\u0430 \u0441\u0432\u043e\u044e \u043e\u0431\u0435\u0440\u0442\u043a\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f:     * &#8212; \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0435     * &#8212; \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441     * &#8212; \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0438 \u0438 \u043e\u0442\u0432\u0435\u0442\u044b \u0441 \u043a\u043e\u0434\u043e\u043c \u043e\u0448\u0438\u0431\u043a\u0438 (4xx, 5xx)     * -&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-478195","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/478195","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=478195"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/478195\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=478195"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=478195"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=478195"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}