Сделано на Python: экспорт статистики ВКонтакте с помощью Prometeus и Grafana

Выпускник курса Python для инженеров Денис Алексеев рассказал о своем проекте, который защитил на итоговой презентации.

755ef7d47ae6fc952577173640a7b859.png

Мой проект помогает упростить экспорт статистики из сообществ в социальных сетях и поставить этот процесс на рельсы автоматизации. С ним поначалу были сложности. Надо было взять реальную задачу и сделать ее на Python, но моя основная работа связана с написанием микросервисов на Go, и задачи на Пайтоне носят скорее вспомогательный характер. Конечно, на курсе была возможность поговорить с наставниками и получить задачу от них, но хотелось чего-то своего.

Дальше события развивались стремительно.

В марте 22 года в связи с санкциями стало наблюдаться возрождение исконно русской социальной сети ВКонтакте. Давно покинутые паблики и сообщества оживали и наполнялись новым контентом, новыми пользователями. У SMM-щиков наблюдался богатый урожай на новых клиентов и головная боль с обработкой запросов.

У меня есть несколько друзей, которые занимаются продвижением сообществ ВКонтакте. Весной этого года у них появилось множество заказов и, как следствие, необходимость в удобном отображении некоторых значений статистики сообществ — если не в масштабе реального времени, то хотя бы автоматически. На ум пришли панельки Grafana, в которых можно не только отслеживать нужные параметры, но и компоновать их различными способами. Допустим, вывести на одной панели посещаемость всех сообществ определенной тематики.

В это время на курсе как раз проходили создание Prometheus Exporter.

В общем, я решил попробовать экспортировать статистику сообщества ВКонтакте, в Prometeus и вывести ее в Grafana. Сразу говорю, что полностью проект завершить не удалось в связи с хроническим отсутствием времени, но показать кое-что интересное, я надеюсь, у меня получится.

Логика работы простая, как три копейки.

  1. Описываем набор желаемых метрик для экспорта в Prometheus и web-сервис, который сможет авторизоваться ВКонтакте и получить оттуда статистику.

  2. Авторизовываемся в соцсети и получаем access_token (как это делается, можно посмотреть в документации).

  3. Делаем метод, который будет обращаться к API, получать статистику и отправлять ее в Prometheus.

  4. Создаем тред, который будет вызывать метод сбора статистики и ждать определенный промежуток времени (промежуток задается в конфигурации, о ней не забываем).

  5. Не забываем также о graceful shutdown, обработке Sigterm и прочих полезных вещах.

Давайте остановимся на некоторых из этих шагов подробнее. Отправка набора метрик делается вот таким образом:

class VKMetrics:
	"""
	Экспортер метрик группы вконтакте,
	"""
	metrics = {}

	def collect(self):
    	group_activity_views = GaugeMetricFamily(
        	'views_value',
        	'Group views value',
        	labels=['group_name']
    	)
    	group_activity_reposts = GaugeMetricFamily(
        	'reposts_value',
        	'Group reposts value',
        	labels=['group_name']
    	)
    	group_activity_likes = GaugeMetricFamily(
        	'likes_value',
        	'Group likes value',
        	labels=['group_name']
    	)
    	group_activity_comments = GaugeMetricFamily(
        	'comments_value',
        	'Group comments value',
        	labels=['group_name']
    	)
    	group_activity_subscribed = GaugeMetricFamily(
        	'subscribed_value',
        	'Group subscribed value',
        	labels=['group_name']
    	)
    	group_activity_unsubscribed = GaugeMetricFamily(
        	'unsubscribed_value',
        	'Group unsubscribed value',
        	labels=['group_name']
    	)

    	for group, metrics in self.metrics.items():
        	group_activity_views.add_metric([group], metrics['views'])
        	yield group_activity_views
        	group_activity_reposts.add_metric([group], metrics['reposts'])
        	yield group_activity_reposts
        	group_activity_likes.add_metric([group], metrics['likes'])
        	yield group_activity_likes
        	group_activity_comments.add_metric([group], metrics['comments'])
        	yield group_activity_comments
        	group_activity_subscribed.add_metric([group], metrics['subscribed'])
        	yield group_activity_subscribed
        	group_activity_unsubscribed.add_metric([group], metrics['unsubscribed'])
        	yield group_activity_unsubscribed


app = Flask(__name__)
REGISTRY.register(VKMetrics())

Как несложно догадаться, для авторизации используются Flask и достаточно простые методы, описывать которые здесь не вижу смысла: все это легко гуглится.

Давайте также остановимся на методе из пункта 3 выше, который получает статистику группы и отправляет данные в exporter:

@app.route('/stat')
def stat():
	"""

Получение статистики сообщества и отправка ее в Prometheus:

	# https://dev.vk.com/method/stats.get
	if config['token'] is None:
    	print("no token")
    	return ""

	url = f"{vk_method_url}/stats.get"
	now = datetime.now()
	from_time = now.replace(second=0, microsecond=0, minute=0, hour=now.hour) - timedelta(
    	hours=config['interval_hours'])
	to_time = now.replace(second=0, microsecond=0, minute=0, hour=now.hour) + timedelta(
    	hours=1
	)
	params = {
    	"group_id": config['group_id'],
    	"timestamp_from": str(from_time.timestamp()),
    	"timestamp_to": str(to_time.timestamp()),
    	"intervals_count": config['interval_ranges'],
    	"extended": "true",
    	"access_token": config['token'],
    	"v": 5.131
	}
	r = requests.get(url, params=params)
	if r.status_code == 200:
    	js = r.json()
    	response = js["response"][0]
    	visitors = response.setdefault('visitors', {})
    	activity = response.setdefault('activity', {})
    	metrics = VKMetrics.metrics.setdefault(config["screen_name"], {})
    	metrics["views"] = visitors.get("views", 0)
    	metrics["likes"] = activity.get("likes", 0)
    	metrics["reposts"] = activity.get("copies", 0)
    	metrics["comments"] = activity.get("comments", 0)
    	metrics["subscribed"] = activity.get("subscribed", 0)
    	metrics["unsubscribed"] = activity.get("unsubscribed", 0)
    	return js, 200
	else:
    	return f"Error {r.status_code} 
{r.text}", 500

Метод для Prometheus, откуда он будет забирать статистику:

@app.route("/metrics")
def metrics():
	return Response(generate_latest(), mimetype=CONTENT_TYPE_LATEST)

Вот скриншоты из Grafana того, что получилось в результате:

6914fb8455e80e4e364e358cc8d4a0b4.png403d29d53301308f81a24351998f009b.png

Ссылка на репозиторий проекта: https://github.com/widler/vk_exporter. Критика, багрепорты, feature requests приветствуются.

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

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

Я более 10 лет занимаюсь программированием. Профессиональную карьеру начал с PHP и долгое время работал только на нем. Несмотря на хлебную работу и востребованность, постоянно смотрел специализации: узнавал, что нового есть в мире языков программирования. В какой-то момент стало интересно, что за язык Go. И началось всякое, в результате чего я сменил очередную уютную фирму, создающую сайты для зарубежных заказчиков, на одну из компаний, работающих на отечественном рынке. И ни разу об этом не пожалел!

В какой-то момент возникла необходимость понимать скрипты, написанные на Пайтоне. Дело в том, что в нашей компании практически все E2E тесты написаны на этом языке, и при взаимодействии с ребятами из команды тестирования приходится понимать: что тут написано и что хотел сказать автор. Кроме того, по работе часто возникает задача сделать разовую отправку большого числа сообщений в очередь, вызвать метод API с параметрами из csv-файла и т. д. Задачи из разряда »на Go делать смысла особого нет, можно быстренько сделать на Python, запустить и не возвращаться больше к этой задаче».

Начал потихоньку погружаться в тему, но не хватало системности подхода, да и всегда находилось много других задач по работе. На учебу просто не оставалось сил или времени. В какой-то момент решил, что нужно найти курсы, где мне расскажут все с самых основ, посмотрят на код, накидают замечаний. Начал искать курсы, на Слёрм сначала даже не обратил внимания. Но после вечерней школы Kubernetes для разработчиков понял, что зря.

Курс помог мне систематизировать знания по Python и начать писать на нем программы, а не бегать по Stackoverflow в поисках того, что можно доработать напильником. По ходу курса особо проблем не возникало. Смотришь теорию, делаешь практическое задание. Если есть вопросы — спрашиваешь в чате курса в телеге. Просто берешь и делаешь.

От редакции: новый поток курса стартует 16 января и продлится 3 месяца. Посмотреть программу и записаться можно здесь: https://slurm.club/3k8UJc2

© Habrahabr.ru