Автоматический запуск профайлера в New Relic

Date November 19th, 2013 Author Vitaly Agapov

Нет такого понятия, как честный бой. В бою используют любое преимущество и любую возможность.

Анджей Сапковскийн «Кровь эльфов»

nr-profilerНесколько лет назад я уже писал статью про свой игрушечный Perl'овый скриптик, авторизующийся на странице. Новой практической задачи пришлось ждать довольно долго. Но она появилась. После недавнего обновления клиентов New Relic у них появилась возможность профилировать все потоки приложения (Java, Ruby, да хоть PHP), чтобы была возможность определить, в каких тредах и на каких методах происходит потеря времени. Запуск профайлера производится из веб-интерфейса, куда надо сначала залогиниться. А очень хотелось записывать дампы по расписанию или, допустим, по наступлению некоего события вроде слишком высокого времени ответа или высокой загрузки CPU.

А пол-дела уже и сделано. Осталось припомнить основы работы с модулем LWP::UserAgent и посмотреть firebug'ом, как проходит авторизация, подстановка CSRF-токенов  и отправка форм в интерфейсе New Relic.

 

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

001.#!/usr/bin/perl
002.use LWP::UserAgent;
003.use HTML::Entities;
004.use Data::Dumper;
005. 
006.my $debug = 0;
007.my $login = 'mylogin';
008.my $pwd = 'mypassword';
009.my $urlGetLogin = "https://rpm.newrelic.com/login";
010.my $urlPostLogin = "https://rpm.newrelic.com/session";
013.my $profileDuration = 2;
014. 
015.my $ua = LWP::UserAgent->new;
016. 
017.# Забираем страницу с формой логина и получаем куки с идентификатором сессии и находим CSRF-токен
018.my $req = $ua->get($urlGetLogin);
019. 
020.my $csrfToken = getToken($req->content);
021.my $cookie = $req->{_headers}->{'set-cookie'};
022.my $uiSession = getSession($cookie);
023.if (!$uiSession || !$csrfToken || !$req->{_msg} eq "OK") { print "Cannot get login page\n"; exit 1; }
024. 
025.# Отправляем POST на логин, из которого опять забираем новые куки
026.$req = $ua->post($urlPostLogin,
027.    [
028.        'authenticity_token'    => $csrfToken,
029.        'login[email]'      => $login,
030.        'login[password]'   => $pwd,
031.        'login[remember_me]'    => 0,
032.        'login[oauth_signin]'   => '',
033.        'utf8'          => '✓',
034.    ],
035.    cookie => $cookie
036.);
037. 
038.$cookie = $req->{_headers}->{'set-cookie'};
039.my $loggedIn = getLoggedIn($cookie);
040.print Dumper($req) if ($debug);
041. 
042.# Если в куке nr_zd_logged_in нет значения true, значит логин не удался и можно расходиться
043.if ($loggedIn ne 'true') { print "Cannot login\n"; exit 1; }
044. 
045.# Забираем страницу с формой запуска профайлера. Здесь нас опять интересует CSRF-токен, а также Agent-ID.
046.$req = $ua->get($urlGetProfiler,
047.    cookie => $cookie
048.);
049.$csrfToken = getToken($req->content);
050. 
051.print Dumper($req) if ($debug);
052.my $realAgentId = getRealAgentId($req->content);
053. 
054.# И, наконец, POST на запуск профайлера. У нас есть кука с сессией, Agent-ID, CSRF-токен. В общем, всё для успешного запуска
055.$req = $ua->post($urlPostProfiler,
056.        [
057.                'authenticity_token'    => $csrfToken,
058.                'profile[duration]'     => $profileDuration,
059.                'profile[real_agent_id]'=> $realAgentId,
060.                'utf8'          => '✓',
061.        ],
062.        cookie => $cookie
063.);
064. 
065.# В случае успешного запроса мы должны вывести "ОК"
066.print $req->{_msg};
067.print Dumper($req) if ($debug);
068. 
069.exit 0;
070. 
071.# Функции для парсинга заголовков и тел сообщений
072.sub getToken {
073.    my $content = shift;
074.    if ($content =~ /<meta name="csrf-token" content="(.+?)"\/>/) {
075.        # В токене могут присутствовать HTML-коды, поэтому нам пригодится модуль HTML::Entities и функция decode_entities
076.        return decode_entities($1);
077.    }
078.    return 0;
079.}
080.sub getRealAgentId {
081.        my $content = shift;
082.        if ($content =~ /name="profile\[real_agent_id\]" type="radio" value="(\d+)"/) {
083.                return $1;
084.        }
085.        return 0;
086.}
087.sub getSession {
088.    my $cookie = shift;
089.    if ($cookie =~ /_newrelic_ui_session=(.+?);/) {
090.        return $1;
091.    }
092.    return 0;
093.}
094.sub getLoggedIn {
095.    my $cookie = shift;
096.    foreach (@{$cookie}) {
097.        if (/nr_zd_logged_in=(.+?);/) {
098.            return $1;
099.        }
100.    }
101.    return 0;
102.}

Tags:
Category: Perl | No comments »

Comments

Leave a comment

 Comment Form