====== Grafana ======
===== Установка =====
# (не работает, была смена ключей, надо какой то другой ключ импортировать, хз какой)
# Добавляем ключи и репозиторий:
apt install gnupg2 && wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add -
echo "deb https://packages.grafana.com/oss/deb stable main" | sudo tee -a /etc/apt/sources.list.d/grafana.list
# После этого ставим из репозитория
apt update && apt install grafana
# После установки включаем и запускаем сервис
systemctl enabled grafana-server && systemctl start grafana-server
==== Установка из файла ====
[[https://grafana.com/grafana/download|Тут можно посмотреть точную версию из числа доступных]], там же собсна и инструкция есть, пару команд (пользователя заводить вроде не обязательно):
$ wget https://dl.grafana.com/oss/release/grafana_7.1.0_amd64.deb
$ sudo dpkg -i grafana_7.1.0_amd64.deb
==== Настройка cli ====
Сервис работает на порту **3000**, учетка **admin**/**admin**\\
**Плагин для работы с Zabbix**
# grafana-cli plugins install alexanderzobnin-zabbix-app
:!: Путь к заббиксу- http://127.0.0.1/zabbix/api_jsonrpc.php\\
:!: Авторизация похоже через блок "Zabbix API details", блок "Auth" чет не работает\\
**Плагин для изображений в оповещениях**\\
grafana-cli plugins install grafana-image-renderer
# иногда может не работать из за нехватки зависимосетей, проверить можно так:
cd /var/lib/grafana/plugins/grafana-image-renderer
ldd chrome-linux/chrome
# Если есть отсутствующие библиотеки, установить хром вручную
wget https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm
sudo yum install ./google-chrome-stable_current_*.rpm
==== Настройка gui ====
Список элементов в переменной и исключение по регулярке\\
{{:linux:screenshot_6.jpg?direct&600|}}\\
Переменная, фильтруется другой переменной, прометеус\\
{{:linux:sdvcsdfvfdv.jpg?direct&600|}}\\
:!: Алерты
function — функция для расчёта параметра. Возможные значения:
* avg() — среднее значение;
* min() — минимальное значение;
* max() — максимальное значение;
* sum() — сумма всех значений;
* count() — количество значений;
* last() — последнее значение;
* median() — среднее значение по медиане;
* diff() — разница между значениями;
* percent_diff() — разница между значениями в процентах;
* count_non_null() — количество значений, отличных от null;
==== Общее ====
**Единицы измерения в графиках**\\
Для данных есть два варианта, "**SI**" (в килобайте 1000 байт) и "**IEC**" (в килобайте 1024 байт)\\
**EIC**, когда в килобайте 1024 байт еще называют "кибибайтом", когда для расчета используется степень двойки (более традиционная форма для ИТ собсна), обозначается "**КиБ или KiB**"\\
==== Repeat/Перечисление списка элементов ====
Можно сделать автоматический репит графиков, с подстановкой списка из переменной\\
Например переменная со списком хостов, чтобы автоматом создать графики для каждого хоста из списка, в json модели нужно сделать такую иерархию:\\
"summary" это агрегация, создавались в ручную, обычные графики, для перечисления создаем вложенную панель, с указанием "[$HOST]" в имени\\
{{:linux:wiki_0.jpg?direct&800|}}
===== Grafana Loki =====
Система сбора и обработки логов.\\
Для сбора метрик использует агент promtail и хранит данные в TSDB (Time Series Data Base, бд временных рядов).\\
Потребляет мало ресурсов благодаря неполной индексации. Интегрируется с разными системами в т.ч. с самой Grafana.\\
В **promtail** для выборки, хранения и парсинга данных используются метки, эти метки (по типу категорий) можно использовать для анализа/отображения.\\
===== Alerting =====
:!: Шаблоны в новой графане
# Указание шаблона в настройках канала оповещения
{{ template "my_tempate" . }}
# Колво алертов
{{ len .Alerts.Firing }}
{{ len .Alerts.Resolved }}
# Перечислены оповещения и их статус
{{ range .Alerts }} {{ .Status }}: {{ .Labels.alertname }}
{{ end }}
# Вложенные шаблоны:
# определение шаблона
{{ define "my_template" }}
...
{{ end }}
# Использование
summary:
{{ template "my_template" . }}
# Удаление тегов
{{ .Labels.Remove (stringSlice "alertname" "AlertGroup" "grafana_folder") }}
{{ .Labels.alertname}}
# Прием "with"
{{ with .ValueString }}
{{- . | reReplaceAll `\[\s` "" | reReplaceAll `\],\s` "\n" }}
{{ end }}
# Значения графика
{{ .Values.max_mem }}
{{ .ValueString }}
{{- printf "%s - %s" .Labels.instance .Annotations.summary }}
{{ printf "%.2f" .Labels "instance" }}
{{ index $values printf "used_percent" | printf "%.1f" }}
# Так же, хороший совет занести нужные данные в summary/description алерта,
# затем в шаблоне обращаться к этому полю для получения данных
# Поле Description в алерте:
"instance={{ index $labels "instance" }} value={{ index $values "B" }}"
# В шаблоне:
{{ index .Annotations "description" }}
# Переменная (?)
{{- $name := default .Chart.Name .Values.nameOverride }}
:!: Примеры
{{ define "my_template" -}}
{{range .Alerts}}
{{ .Values.used_percent }}
{{ .Labels.alertname}}
{{ index .Annotations "description" }}
{{- end }}
{{ end }}
{{ define "print_alert" }}
Summary: {{ .CommonAnnotations.Values }}
{{ len .Alerts.Firing }} firing alert(s):
{{ if .Alerts.Firing -}}
{{ range .Alerts.Firing -}}
{{ .Labels.Remove (stringSlice "alertname" "AlertGroup" "grafana_folder") }}
{{ with .ValueString }}
{{- . | reReplaceAll `\[\s` "" | reReplaceAll `\],\s` "\n" | reReplaceAll `\]` "" | reReplaceAll `var='[A-Z0-9a-z]+'\s` "" | reReplaceAll `labels=\{[A-Za-z0-9_\-\=\s\.:,]*\}\s` "" | reReplaceAll `metric='(.*)' ` " **$1**: " | reReplaceAll `value=([0-9\.]+)` "$1" }}
{{ end }}
{{- end }}
{{- end }}
{{ len .Alerts.Resolved }} resolved alert(s):
{{ if .Alerts.Resolved -}}
{{ range .Alerts.Resolved -}}
{{ .Labels.Remove (stringSlice "alertname" "AlertGroup" "grafana_folder") }}
{{ with .ValueString }}
{{- . | reReplaceAll `\[\s` "" | reReplaceAll `\],\s` "\n" | reReplaceAll `\]` "" | reReplaceAll `var='[A-Z0-9a-z]+'\s` "" | reReplaceAll `labels=\{[A-Za-z0-9_\-\=\s\.:,]*\}\s` "" | reReplaceAll `metric='(.*)' ` " **$1**: " | reReplaceAll `value=([0-9\.]+)` "$1" }}
{{ end }}
{{- end }}
{{- end }}
{{ end }}
{{ define "my_template" -}}
{{ if .Alerts.Firing }}
**{{ len .Alerts.Firing }} firing alert(s)**
{{ template "summarize" .Alerts.Firing }}
{{- end }}
{{- if .Alerts.Resolved -}}
**{{ len .Alerts.Resolved }} resolved alert(s)**
{{ template "summarize" .Alerts.Resolved }}
{{- end }}
{{- end }}
{{ define "summarize" -}}
{{ range . }}
{{- printf "%s - %s" .Labels.instance .Annotations.summary }}
{{ end }}
{{- end }}
{{ define "mm_title_alert_composite" }}
{{- if eq ((index .Alerts 0).Labels._alert_type_) "CLASSIC" }}
{{- template "mm_title_alert_composite.classic" . }}{{ end }}
{{- if eq ((index .Alerts 0).Labels._alert_type_) "MULTI" }}
{{- template "mm_title_alert_composite.multi" . }}{{ end }}{{ end }}
{{/*MULTI*/}}
{{ define "mm_title_alert_composite.classic" }}
{{if .Alerts.Firing }} [Alerting] {{end}}{{ if .Alerts.Resolved }} [OK] {{end}}{{ .CommonLabels.alertname }}
{{ end }}
{{/*MULTI*/}}
{{ define "mm_title_alert_composite.multi" }}
{{ if and (gt (len .Alerts.Firing) 0) (eq (len .Alerts.Resolved) 0) -}}
[FIRING:{{ len .Alerts.Firing }}] {{ .CommonLabels.alertname }}
{{ else }}{{ if and (gt (len .Alerts.Resolved) 0) (eq (len .Alerts.Firing) 0) -}}
[RESOLVED] {{ .CommonLabels.alertname }}
{{ else -}}
[FIRING:{{ len .Alerts.Firing }},RESOLVED:{{ len .Alerts.Resolved }}] {{ .CommonLabels.alertname }}
{{ end }}{{ end }}{{ end }}
:!: Еще пример
Чтобы получить значение, в правиле, в поле "summary" например пишем переменные
// после "$values" указывается выражение, можно выбрать любое
{{ $labels.group }}: {{ $values.A.Value }}
Пример шаблона
{{ define "tg_body_alert_composite" -}}
{{/* Стремление сделать один шаблон, тут разделение на типы алертов,
с одним инстансом или с мульти, тип задается тегом, в правиле алерта */}}
{{/* Примечательно, отступы здесь == отступы в сообщении, поэтому
некоторые строки здесь выпадают из форматирования и прибиты к левой границе */}}
{{- if eq ((index .Alerts 0).Labels._alert_type_) "CLASSIC" }}
{{- template "tg_body_alert_composite.classic" . }}
{{ else if eq ((index .Alerts 0).Labels._alert_type_) "MULTI" }}
{{- template "tg_body_alert_composite.multi" . }}
{{ else }}
{{- (index .Alerts 0).Labels.alertname }}
Label '_alert_type_' is not defined or invalid
{{ end }}
{{- end }}
{{/* Тип алертов с одним инстансом (CLASSIC) */}}
{{ define "tg_body_alert_composite.classic" -}}
{{/* Возникновение алерта */}}
{{- if .Alerts.Firing -}}
{{ range .Alerts }}[Alerting] {{ .Labels.alertname }}
{{ if .Annotations.description }}
{{ .Annotations.description }}
{{ end }}
Metrics:
{{- $value_of_metric := (.ValueString | reReplaceAll `.*metric='` "" | reReplaceAll `' labels.*` "") -}}
{{ if ne $value_of_metric "Value" }}
{{ with .ValueString }}
{{- . | reReplaceAll `\[\s` "" | reReplaceAll `\],\s` "\n" | reReplaceAll `\]` "" | reReplaceAll `var='[A-Z0-9a-z]+'\s` "" | reReplaceAll `labels=\{[A-Za-z0-9_\-\=\s\.:,]*\}\s` "" | reReplaceAll `metric='(.*)' ` " $1: " | reReplaceAll `value=([0-9\.]+)` "$1" }}
{{ end }}
{{ else }}
{{ with .ValueString }}
{{- . | reReplaceAll `\[\s` "" | reReplaceAll `\],\s` "\n" | reReplaceAll `\]` "" | reReplaceAll `var='[A-Z0-9a-z]+'\s` "" | reReplaceAll `metric='.*'\s` "" | reReplaceAll `labels={.*=(.*)}` " $1: " | reReplaceAll `value=([0-9\.]+)` "$1" }}
{{- end }}
{{- end -}}
{{- if .PanelURL }}
Panel URL: {{ .PanelURL }}
{{ end }}
{{ end }}
{{ end -}}
{{/* Решение алерта */}}
{{- if .Alerts.Resolved -}}
{{ range .Alerts }}[OK] {{ .Labels.alertname }}
{{ .Annotations.description }}
{{- end }}
{{- end -}}
{{ end }}
{{/* Тип алерта, когда много инстансов (MULTI) */}}
{{ define "tg_body_alert_composite.multi" -}}
{{ if (index .Alerts 0).Annotations.description -}}
{{ (index .Alerts 0).Annotations.description -}}
{{ end -}}
{{/* Если состояние Firing, перечисляем переданные инстансы в подшаблоне "summarize_large" */}}
{{- if .Alerts.Firing }}
**{{ len .Alerts.Firing }} firing alert(s)**
{{ template "tg_body_alert_composite.multi.summarize_large" .Alerts.Firing }}
{{ end -}}
{{/* Аналогично для состояния Resolve */}}
{{- if .Alerts.Resolved }}
**{{ len .Alerts.Resolved }} resolved alert(s)**
{{- template "tg_body_alert_composite.multi.summarize_large" .Alerts.Resolved -}}
{{ end -}}
{{ if (index .Alerts 0).PanelURL }}
Panel URL: {{ (index .Alerts 0).PanelURL }}
{{- end }}
{{- end }}
{{/* Подшаблон для перечисления инстансов в цикле */}}
{{ define "tg_body_alert_composite.multi.summarize_large" }}
{{- range . -}}
{{/* Пишем поле "summary" каждого инстанса т.к.
в алерте там переменные с данными */}}
{{ index .Annotations "summary" -}}
{{ end -}}
{{ end }}
===== Еще про алерты =====
:!: Параметры
Собсна в простом случае, запросом получаем какие то данные, первое выражение для агрегации данных, второе для оценки состояния\\
{{:linux:graf_1.png?direct&600|}}\\
{{:linux:graf_0.png?direct&600|}}\\
:!:
:!:
===== API =====
:!: Auth
curl http://admin:admin@localhost:3000/api/org
:!: silence
Получить перечень
curl -X 'GET' 'http://admin:admin@192.168.0.14:3000/api/alertmanager/grafana/api/v2/silences' \
-H 'accept: application/json'
http://192.168.0.14:3000/api/alertmanager/grafana/api/v2/silences
Создать новый
curl -X 'POST' \
'http://admin:admin@192.168.0.14:3000/api/alertmanager/grafana/api/v2/silences' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"comment": "comment_string",
"createdBy": "automatic_rule",
"startsAt": "2024-01-27T07:00:00.000Z",
"endsAt": "2024-01-27T09:00:00.000Z",
"matchers": [
{
"isEqual": true,
"isRegex": false,
"name": "name",
"value": "my_four_alert"
}
]
}'