Skip to content

Commit 7ff01e5

Browse files
committed
Начальный импорт
0 parents  commit 7ff01e5

File tree

13 files changed

+1495
-0
lines changed

13 files changed

+1495
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.generated/*
2+
.tools/*

Makefile

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
.DEFAULT_GOAL := help
2+
SHELL := /bin/bash
3+
M = $(shell printf "\033[34;1m>>\033[0m")
4+
rwildcard = $(foreach d,$(wildcard $(1:=/*)),$(call rwildcard,$d,$2) $(filter $(subst *,%,$2),$d))
5+
6+
TARGET_NAME = $(firstword $(MAKECMDGOALS))
7+
RUN_ARGS = $(filter-out $@, $(MAKEOVERRIDES) $(MAKECMDGOALS))
8+
OS := $(shell uname -s)
9+
TOOLS_DIR ?= .tools
10+
SUDO_PASSWORD ?= human
11+
12+
VECTOR_VERSION ?= 0.35.0
13+
# если установлен в системе, то доступен как команда в /usr/bin/vector
14+
VECTOR_BINARY ?= $(TOOLS_DIR)/vector_$(VECTOR_VERSION)_$(OS)_amd64
15+
VECTOR_CONFIG_DIR ?= $(PWD)/.generated/vector_config
16+
YQ_VERSION ?= 4.30.5
17+
JV_VERSION ?= 0.4.0
18+
19+
20+
ifeq ($(OS), Darwin)
21+
VECTOR_TAR_URL := https://packages.timber.io/vector/$(VECTOR_VERSION)/vector-$(VECTOR_VERSION)-x86_64-apple-darwin.tar.gz
22+
VECTOR_TAR_BIN_PATH := ./vector-x86_64-apple-darwin/bin/vector
23+
else
24+
VECTOR_TAR_URL := https://packages.timber.io/vector/$(VECTOR_VERSION)/vector-$(VECTOR_VERSION)-x86_64-unknown-linux-gnu.tar.gz
25+
VECTOR_TAR_BIN_PATH := ./vector-x86_64-unknown-linux-gnu/bin/vector
26+
endif
27+
28+
YQ_BINARY := $(TOOLS_DIR)/yq_$(YQ_VERSION)_$(OS)_amd64
29+
JV_BINARY := $(TOOLS_DIR)/jv_$(JV_VERSION)_$(OS)_amd64
30+
31+
YQ_BINARY_URL := https://github.com/mikefarah/yq/releases/download/v$(YQ_VERSION)/yq_$(OS)_amd64
32+
33+
34+
.PHONY: install-dependencies
35+
install-dependencies: ## Install required dependencies
36+
mkdir -p $(TOOLS_DIR)
37+
ifeq (,$(wildcard $(YQ_BINARY)))
38+
wget -qO $(YQ_BINARY) $(YQ_BINARY_URL) --show-progress && chmod +x $(YQ_BINARY)
39+
endif
40+
ifeq (,$(wildcard $(JV_BINARY)))
41+
$(info $(M) Building jv from source...)
42+
GO111MODULE="on" GOBIN=$(shell realpath $(TOOLS_DIR)) go install github.com/santhosh-tekuri/jsonschema/cmd/jv@v$(JV_VERSION)
43+
mv $(TOOLS_DIR)/jv $(JV_BINARY)
44+
endif
45+
46+
47+
.PHONY: install-dev-dependencies
48+
install-dev-dependencies: ## Install required dev tools
49+
$(info $(M) Install required dev tools...)
50+
ifneq ($(CI), true)
51+
# Local environment as GitLab CI/CD environment var not definded or != true
52+
@echo "Check if python installed"
53+
@command -v pip >/dev/null 2>&1 && echo "OK" || { \
54+
echo "$(M) Installing python3 pip..."; \
55+
echo "$(M) You may be prompted for sudo password..."; \
56+
if [ "$(OS)" = "Darwin" ]; then \
57+
brew install python3 && (curl https://bootstrap.pypa.io/get-pip.py | python3) \
58+
else \
59+
sudo apt-get update && (sudo apt-get install python3 && curl https://bootstrap.pypa.io/get-pip.py | python3) \
60+
fi; \
61+
}
62+
endif
63+
python3 -m pip install -r ./dev-requirements.txt
64+
65+
66+
67+
.PHONY: download-vector-bin
68+
download-vector-bin: ## Download vector.dev binary
69+
ifeq (,$(wildcard $(VECTOR_BINARY)))
70+
$(info $(M) Download vector.dev $(VECTOR_BINARY) binary...)
71+
@wget -qO- https://packages.timber.io/vector/$(VECTOR_VERSION)/vector-$(VECTOR_VERSION)-x86_64-unknown-linux-gnu.tar.gz --show-progress \
72+
| tar xvzf - -C $(TOOLS_DIR) "$(VECTOR_TAR_BIN_PATH)" --strip-components=3 \
73+
&& chmod +x $(TOOLS_DIR)/vector && mv $(TOOLS_DIR)/vector $(VECTOR_BINARY)
74+
endif
75+
76+
77+
.PHONY: validate-metrics-catalog-spec
78+
validate-metrics-catalog-spec: ## Validates metrics-catalog.yml
79+
$(info $(M) Validate vars/metric-catalog.yml with json-schema...)
80+
$(JV_BINARY) ./schema/vectordev-metrics-catalog.json ./ansible-playbook/vars/metrics-catalog.yml
81+
82+
83+
.PHONY: lint-vector-config
84+
lint-vector-config: ## Check vector files for invalid or deprecated functions
85+
$(info $(M) Check for deprecated functions vector.dev...)
86+
@FOUND_FILES=$$(grep -r -l "to_timestamp" files/); \
87+
if [ -n "$$FOUND_FILES" ]; then \
88+
echo "ERROR: Some files contain deprecated to_timestamp func, replace with parse_timestamp (see https://vector.dev/highlights/2023-08-15-0-32-0-upgrade-guide/#deprecations)"; \
89+
echo "$$FOUND_FILES"; \
90+
exit 1; \
91+
else \
92+
echo "OK"; \
93+
exit 0; \
94+
fi
95+
96+
.PHONY: generate-vector-conf
97+
generate-vector-conf: | validate-metrics-catalog-spec lint-vector-config ## Generate vector.dev at localhost
98+
@mkdir -p $(VECTOR_CONFIG_DIR)
99+
$(info $(M) Ansible generates vector.dev config for localhost...)
100+
$(eval $@_tmpfile := $(shell mktemp ansible-playbook/playbook.tmpXXX))
101+
@$(YQ_BINARY) ea '.[0].hosts = "127.0.0.1", .[0].connection = "local"' ./ansible-playbook/playbook.yml > $($@_tmpfile)
102+
@$(YQ_BINARY) -i ea 'del(.[0].roles)' $($@_tmpfile)
103+
104+
@echo Build and copy config files...
105+
VECTOR_KAFKA_PASSWORD=fake \
106+
VECTOR_KAFKA_USERNAME=fake \
107+
ansible-playbook -connection=local --inventory localhost, $($@_tmpfile) \
108+
--tags aggregator \
109+
--extra-vars "development_mode=true" \
110+
--extra-vars "ansible_sudo_pass=$(SUDO_PASSWORD)" \
111+
--extra-vars "local_build=true" \
112+
--extra-vars "vector_config_dir=$(VECTOR_CONFIG_DIR)" \
113+
--extra-vars "vector_kafka_bootstrap_servers=FAKE_KAFKA_SERVER" \
114+
--extra-vars "vector_kafka_topics=FAKE_KAFKA_TOPIC" \
115+
--skip-tags install,setup
116+
@rm -rf $($@_tmpfile)
117+
# popd
118+
119+
.PHONY: validate-vector-conf
120+
validate-vector-conf: generate-vector-conf ## Validate current vector.dev config
121+
$(info $(M) Validate vector config at $(VECTOR_CONFIG_DIR)...)
122+
$(VECTOR_BINARY) validate -C $(VECTOR_CONFIG_DIR) --no-environment
123+
124+
.PHONY: test-vector-transfroms
125+
test-vector-transfroms: | generate-vector-conf validate-vector-conf ## Run vector.dev transform tests
126+
$(info $(M) Run transforms tests with config $(VECTOR_CONFIG_DIR)...)
127+
$(VECTOR_BINARY) test $(VECTOR_CONFIG_DIR)/*_sources_*.toml $(VECTOR_CONFIG_DIR)/*transforms_*.toml $(VECTOR_CONFIG_DIR)/*_tests_*.toml
128+
129+
.PHONY: test-vector-transfrom
130+
test-vector-transfrom: ## Run vector.dev test for a specifed test file
131+
ifndef file
132+
@echo "To run use file=testfile make ..."
133+
else
134+
$(info $(M) Run a transform test with config $(VECTOR_CONFIG_DIR)...)
135+
@echo Test file: $(file)
136+
$(VECTOR_BINARY) test $(VECTOR_CONFIG_DIR)/*_sources_*.toml $(VECTOR_CONFIG_DIR)/*transforms_*.toml $(file)
137+
endif
138+
139+
help: ## Show this help
140+
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
141+
142+
%:
143+
@:

README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Преобразование логов http accesslog в метрики с vector.dev
2+
3+
В данном каталоге лежат файлы описывающий подход, позволяющий генерировать метрики из логов без переписывания кода трансформов под каждый сервис.
4+
5+
1. Полагаемся на то, что все сервисы пишут логи в фиксированном формате JSON и имеют одинаковый набор обязательных полей. См. [example_logs]
6+
2. Для кодогенерации использован Ansible и jinja2 шаблоны. Генерируем toml файлы конфигурации vector.dev и тесты к ним, где нужно.
7+
3. Метрики определяются в файле [ansible-playbook/vars/metrics-catalog.yml], после этого запускаем генерацию через ansible. См пример в Makefile
8+
4. Отдельной задачей конфигурации выгружаются на серверы с агрегаторами vector.dev, и для применения новой конфигурации выполняется перезапуск процесса vector
9+
10+
## Что нам дал рефакторинг
11+
12+
* Мы вместо 5 часов теперь тратим 10-30 минут на добавление/изменение метрик с учетом выкатки на прод
13+
* Появилась автоматическая валидация по схеме, теперь ошибку при описании метрки допустить сложнее
14+
* Теперь для добавления новой метрки не нужно знать как это закодировать на языку VRL - достаточно YAML девелопера )
15+
16+
17+
## Ограничения
18+
19+
Данный код является ознакомительным и не представляет собой готовое решение, вы можете придумать свое на основе данных идей.
20+
Потому мы не приводим полные конфигурации vector.dev, код развертывания и полный набор ansible файлов для playbook.
21+
Однако вы можете сгенерировать по файлу [ansible-playbook/vars/metrics-catalog.yml] файлы конфигурации vector и посмотреть как они выглядят.
22+
23+
## Генерирование файлов конфигурации
24+
25+
1. Используйте Ubuntu Linux (или Debian)
26+
2. Запустите `make install-dependencies` и `make install-dev-dependencies`
27+
3. Запустите `make download-vector-bin` - установить файлы vector для валидации запуска тестов
28+
4. Выполните сборку и тесты `make test-vector-transfroms`
29+
5. Созданные файлы смотрите в каталоге [.generated/vector_config]
30+
31+
## Контакты
32+
33+
Если вам интересны подробности вы можете писать нам, см. сайт https://vitech.team/ ("По вопросам сотрудничества") или приходите работать к нам.

ansible-playbook/playbook.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
- name: Configure aggregator
3+
hosts: aggregator
4+
vars:
5+
development_mode: false
6+
vector_user_configs_paths:
7+
- "{{ playbook_dir }}/../files/aggregator"
8+
clickhouse_local_endpoint: "{{ hostvars[inventory_hostname].clickhouse_local_endpoint }}"
9+
vector_kafka_sasl_password: "{{ lookup('ansible.builtin.env', 'VECTOR_KAFKA_PASSWORD') }}"
10+
vector_kafka_sasl_username: "{{ lookup('ansible.builtin.env', 'VECTOR_KAFKA_USERNAME') }}"
11+
vars_files:
12+
- "{{ playbook_dir }}/vars/metrics-catalog.yml"
13+
ignore_errors: true
14+
tasks:
15+
- name: "Local Build. Generate Vector Config Files"
16+
ansible.builtin.include_tasks: tasks/vector_config_generate_tasks.yml
17+
when: local_build | default(False)
18+
19+
tags:
20+
- aggregator
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
---
2+
- name: Remove generated vector configs dir
3+
ansible.builtin.file:
4+
state: absent
5+
path: "{{ playbook_dir }}/../.generated/vector_configs/"
6+
delegate_to: localhost
7+
8+
- name: Find user-defined configs
9+
find:
10+
path: "{{ vector_user_configs_path }}"
11+
recurse: yes
12+
patterns: "*.toml.j2"
13+
when: vector_user_configs_paths is defined
14+
become: false
15+
delegate_to: localhost
16+
register: custom_configs
17+
loop_control:
18+
loop_var: vector_user_configs_path
19+
loop: "{{ vector_user_configs_paths }}"
20+
21+
- name: Merging a list of files
22+
set_fact:
23+
custom_configs: "{{ custom_configs.results | map(attribute='files') | flatten }}"
24+
25+
- name: Create generated vector configs dir
26+
ansible.builtin.file:
27+
state: directory
28+
path: "{{ playbook_dir }}/.generated/vector_configs/"
29+
mode: 0777
30+
delegate_to: localhost
31+
32+
- name: Generate vector configs
33+
become: false
34+
template:
35+
src: "{{ item.path }}"
36+
dest: "{{ vector_config_dir }}/\
37+
{{ (item.path | dirname).split('/')[-2] }}_\
38+
{{ (item.path | dirname).split('/')[-1] }}_\
39+
{{ item.path | basename | replace('.j2', '') | replace ('/', '_') }}"
40+
mode: "0666"
41+
loop: "{{ custom_configs }}"
42+
when: custom_configs is defined
43+
delegate_to: localhost
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# yaml-language-server: $schema=../schema/vectordev-metrics-catalog.json
2+
metrics_catalog:
3+
defaults:
4+
# в какой label из какого поля брать значение
5+
label_logfield_mapping: &default_label_logfield_mapping
6+
path: "http_path"
7+
method: "http_method"
8+
status: "http_status_code"
9+
cluster_name: "cluster_name"
10+
container_name: "container_name"
11+
service_name: "service_name"
12+
exclude_events:
13+
- selector: Исключаем из метрик логи канарееченого релиза, которые получен для запросов из внутренней сети. Чтобы это не попадало SLO
14+
filter:
15+
is_internal_traffic:
16+
eq: "1"
17+
namespace:
18+
eq: "shop-production"
19+
service_name:
20+
re: "^.*-canary(-.*)?$"
21+
22+
metrics:
23+
vi_http:
24+
# Метрика vi_http_requests_total
25+
requests_total: # требуется для transforms.metrics-http-accesslog-k8s
26+
metric_type: counter
27+
group_by_logfield: &global_http_requests_total_status_code http_status_code # по какому полю считаем, число событий (даст в итоге status=200: 1013, status=500: 1)
28+
label_logfield_mapping: *default_label_logfield_mapping
29+
event_selectors: &global_http_requests_total_event_selectors
30+
# фильтры подходящих нам метирик
31+
##
32+
## Метрики Интернет магазина
33+
##
34+
- selector: "Запросы к главной странице интернет магазина"
35+
filter:
36+
http_path: # имя поля в событии лога (входящие данные трансформа vector.dev)
37+
# возможные условия отбора: eq -> ==, neq -> !=, re -> match_any(), nre -> !match_any.
38+
# Порядок вычисления условий в группе: neq, nre, eq, re, (oneOfRe - не реализован)
39+
eq: "/" # оператор и значение для сравнениея
40+
namespace:
41+
eq: "shop-production"
42+
service_name:
43+
re: "^shop-service(?:-canary)?$"
44+
http_method:
45+
eq: "GET"
46+
- selector: "Запросы на создание заказа в интернет магазине"
47+
filter:
48+
http_path:
49+
re: "^/order$|^/order-fast$"
50+
namespace:
51+
eq: "shop-production"
52+
service_name:
53+
re: "^shop-service(?:-canary)?$"
54+
- selector: "Открытие страницы производителя в интернет магазине"
55+
filter:
56+
http_path:
57+
re: "^/vendor/(?P<name>([^/]+/)+)$"
58+
label_override: "/vendor/:name"
59+
namespace:
60+
eq: "shop-production"
61+
service_name:
62+
re: "^shop-service(?:-canary)?$"
63+
# Метрика vi_http_request_duration_seconds
64+
request_duration_seconds: # требуется для transforms.metrics-http-accesslog-k8s - бакеты определены там
65+
metric_type: histogram
66+
group_by_logfield: "duration_sec"
67+
label_logfield_mapping: *default_label_logfield_mapping
68+
event_selectors: *global_http_requests_total_event_selectors

dev-requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ansible==5.3.0
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Пример записи лога получаемого из приложения nginx
2+
3+
{
4+
"time": "2023-02-13T10:23:07.987000123+03:00",
5+
"request_id": "6a432b1e521b042789c1e984aee21127",
6+
"user": "",
7+
"address": "101.11.22.33",
8+
"bytes_received": 4799,
9+
"bytes_sent": 14720,
10+
"protocol": "HTTP/1.1",
11+
"scheme": "http",
12+
"method": "GET",
13+
"host": "internal-products",
14+
"path": "/product/122",
15+
"request_uri": "/product/122?full=true",
16+
"request_query": "?full=true",
17+
"referrer": "https://www.yandex.ru/search",
18+
"user_agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:108.0) Gecko/20100101 Firefox/108.0",
19+
"request_time": 0.3,
20+
"status": 200,
21+
"upstream_addr": "127.0.0.1:4000",
22+
"upstream_bytes_received": 14693,
23+
"upstream_response_time": 0.217,
24+
"upstream_status": "200"
25+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[sinks.access_log_metrics]
2+
type = "prometheus_exporter"
3+
inputs = [ "metrics-cardinality-limiter" ]
4+
address = "0.0.0.0:9598"
5+
buckets = [0.005, 0.01, 0.1, 0.2, 0.4, 0.5, 0.8, 1, 2, 2.5, 3, 4, 5, 10, 15, 20]
6+
flush_period_secs = 60
7+
default_namespace = "service"
8+
quantiles = [0.5, 0.75, 0.9, 0.95, 0.99]
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
[sources.kafka_raw]
2+
type = "kafka"
3+
bootstrap_servers = "{{ vector_kafka_bootstrap_servers | join(',') }}"
4+
group_id = "vector"
5+
topics = [ "{{ vector_kafka_topics | join('", "') }}" ]
6+
7+
8+
[transforms.kafka]
9+
type = "remap"
10+
inputs = ["kafka_raw"]
11+
drop_on_error = true
12+
source = """
13+
del(.headers)
14+
del(.message_key)
15+
del(.offset)
16+
del(.partition)
17+
del(.topic)
18+
del(.timestamp_end)
19+
del(._partial)
20+
"""

0 commit comments

Comments
 (0)