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

Date November 19th, 2013 Author Vitaly Agapov

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

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

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

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

 

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

#!/usr/bin/perl
use LWP::UserAgent;
use HTML::Entities;
use Data::Dumper;

my $debug = 0;
my $login = 'mylogin';
my $pwd = 'mypassword';
my $urlGetLogin = "https://rpm.newrelic.com/login";
my $urlPostLogin = "https://rpm.newrelic.com/session";
my $urlGetProfiler = "https://rpm.newrelic.com/accounts/my_acc_id/applications/my_app_id/profiles";
my $urlPostProfiler = "https://rpm.newrelic.com/accounts/my_acc_id/applications/my_app_id/profiles";
my $profileDuration = 2;

my $ua = LWP::UserAgent->new;

# Забираем страницу с формой логина и получаем куки с идентификатором сессии и находим CSRF-токен
my $req = $ua->get($urlGetLogin);

my $csrfToken = getToken($req->content);
my $cookie = $req->{_headers}->{'set-cookie'};
my $uiSession = getSession($cookie);
if (!$uiSession || !$csrfToken || !$req->{_msg} eq "OK") { print "Cannot get login page\n"; exit 1; }

# Отправляем POST на логин, из которого опять забираем новые куки
$req = $ua->post($urlPostLogin,
	[
		'authenticity_token'	=> $csrfToken,
		'login[email]'		=> $login,
		'login[password]'	=> $pwd,
		'login[remember_me]'	=> 0,
		'login[oauth_signin]'	=> '',
		'utf8'			=> '✓',
	],
	cookie => $cookie
);

$cookie = $req->{_headers}->{'set-cookie'};
my $loggedIn = getLoggedIn($cookie);
print Dumper($req) if ($debug);

# Если в куке nr_zd_logged_in нет значения true, значит логин не удался и можно расходиться
if ($loggedIn ne 'true') { print "Cannot login\n"; exit 1; }

# Забираем страницу с формой запуска профайлера. Здесь нас опять интересует CSRF-токен, а также Agent-ID.
$req = $ua->get($urlGetProfiler,
	cookie => $cookie
);
$csrfToken = getToken($req->content);

print Dumper($req) if ($debug);
my $realAgentId = getRealAgentId($req->content);

# И, наконец, POST на запуск профайлера. У нас есть кука с сессией, Agent-ID, CSRF-токен. В общем, всё для успешного запуска
$req = $ua->post($urlPostProfiler,
        [
                'authenticity_token'    => $csrfToken,
                'profile[duration]'     => $profileDuration,
                'profile[real_agent_id]'=> $realAgentId,
                'utf8'			=> '✓',
        ],
        cookie => $cookie
); 

# В случае успешного запроса мы должны вывести "ОК"
print $req->{_msg};
print Dumper($req) if ($debug);

exit 0;

# Функции для парсинга заголовков и тел сообщений
sub getToken {
	my $content = shift;
	if ($content =~ /<meta name="csrf-token" content="(.+?)"\/>/) {
		# В токене могут присутствовать HTML-коды, поэтому нам пригодится модуль HTML::Entities и функция decode_entities
		return decode_entities($1);
	}
	return 0;
}
sub getRealAgentId {
        my $content = shift;
        if ($content =~ /name="profile\[real_agent_id\]" type="radio" value="(\d+)"/) {
                return $1;
        }
        return 0;
}
sub getSession {
	my $cookie = shift;
	if ($cookie =~ /_newrelic_ui_session=(.+?);/) {
		return $1;
	}
	return 0;
}
sub getLoggedIn {
	my $cookie = shift;
	foreach (@{$cookie}) {
		if (/nr_zd_logged_in=(.+?);/) {
			return $1;
		}
	}
	return 0;
}

Tags:
Category: Perl | No comments »

Comments

Leave a comment

 Comment Form