Aféierung
Beim Ofbau vun engem anere System ware mir konfrontéiert mat der Bedierfnes fir eng grouss Zuel vu verschiddene Logbicher ze veraarbecht. ELK gouf als Tool gewielt. Dësen Artikel wäert eis Erfarung diskutéieren beim Ariichten vun dësem Stack.
Mir setzen net en Zil fir all seng Fäegkeeten ze beschreiwen, mä mir wëllen eis speziell op d'Léisung vu praktesche Problemer konzentréieren. Dëst ass wéinst der Tatsaach, datt och wann et eng zimlech grouss Quantitéit vun Dokumentatioun a prett-feieren Biller ass, sinn et relativ vill Fallen, op d'mannst hu mir se fonnt.
Mir hunn de Stack iwwer Docker-compose ofgesat. Ausserdeem hate mir eng gutt geschriwwen docker-compose.yml, déi eis erlaabt de Stack bal ouni Problemer ze erhéijen. An et huet eis geschéngt datt d'Victoire scho no wier, elo wäerte mir et e bëssen upassen fir eise Besoinen ze passen an dat ass et.
Leider war de Versuch de System ze konfiguréieren fir Logbicher vun eiser Applikatioun ze kréien an ze veraarbechten net direkt erfollegräich. Dofir hu mir décidéiert datt et derwäert wier all Komponent separat ze studéieren, an dann zréck op hir Verbindungen.
Also hu mir ugefaang mat Logstash.
Ëmfeld, Deployment, Lafen Logstash an engem Container
Fir Deployment benotze mir Docker-compose; d'Experimenter, déi hei beschriwwe ginn, goufen op MacOS an Ubuntu 18.0.4 duerchgefouert.
Образ logstash, который был прописан у нас в исходном docker-compose.yml, это docker.elastic.co/logstash/logstash:6.3.2
Mir wäerten et fir Experimenter benotzen.
Mir hunn eng separat docker-compose.yml geschriwwen fir Logstash ze lafen. Natierlech war et méiglech d'Bild vun der Kommandozeil ze lancéieren, awer mir hunn e spezifesche Problem geléist, wou mir alles aus Docker-compose lafen.
Kuerz iwwer Configuratiounsdateien
Wéi aus der Beschreiwung follegt, kann Logstash entweder fir ee Kanal lafen, an deem Fall muss et d'*.conf Datei passéieren, oder fir verschidde Kanäl, an deem Fall muss et d'Pipelines.yml Datei passéieren, déi am Tour , wäert op d'Fichier'en .conf fir all Kanal verbannen.
Мы пошли по второму пути. Он нам показался более универсальным и масштабируемым. Поэтому, мы создали pipelines.yml, и сделали директорию pipelines, в которую будем класть файлы .conf для каждого канала.
Внутри контейнера есть ещё один конфигурационный файл — logstash.yml. Мы его не трогаем, используем как есть.
Also, eis Verzeechnesstruktur:
Для получения входных данных пока считаем, что это tcp по порту 5046, а для вывода будем использовать stdout.
Hei ass eng einfach Konfiguratioun fir den éischte Start. Well déi éischt Aufgab ass ze starten.
Also, mir hunn dës docker-compose.yml
version: '3'
networks:
elk:
volumes:
elasticsearch:
driver: local
services:
logstash:
container_name: logstash_one_channel
image: docker.elastic.co/logstash/logstash:6.3.2
networks:
- elk
ports:
- 5046:5046
volumes:
- ./config/pipelines.yml:/usr/share/logstash/config/pipelines.yml:ro
- ./config/pipelines:/usr/share/logstash/config/pipelines:ro
Wat gesi mer hei?
- Networks и volumes были взяты из исходного docker-compose.yml (тот где целиком стек запускается) и думаю, что сильно здесь на общую картинку не влияют.
- Мы создаём один сервис (services) logstash, из образа docker.elastic.co/logstash/logstash:6.3.2 и присваиваем ему имя logstash_one_channel.
- Mir weider port 5046 am Container, op déi selwecht intern port.
- Мы отображаем наш файл настройки каналов ./config/pipelines.yml на файл /usr/share/logstash/config/pipelines.yml внутри контейнера, откуда его подхватит logstash и делаем его read-only, просто на всякий случай.
- Мы отображаем директорию ./config/pipelines, где у нас лежат файлы с настройками каналов, в директорию /usr/share/logstash/config/pipelines и тоже делаем её read-only.
Pipelines.yml Datei
- pipeline.id: HABR
pipeline.workers: 1
pipeline.batch.size: 1
path.config: "./config/pipelines/habr_pipeline.conf"
Ee Kanal mat dem HABR Identifizéierer an de Wee zu senger Konfiguratiounsdatei ginn hei beschriwwen.
A schliisslech d'Datei "./config/pipelines/habr_pipeline.conf"
input {
tcp {
port => "5046"
}
}
filter {
mutate {
add_field => [ "habra_field", "Hello Habr" ]
}
}
output {
stdout {
}
}
Loosst eis elo net op seng Beschreiwung goen, loosst eis probéieren et auszeféieren:
docker-compose up
Wat gesi mir?
De Container huet ugefaang. Mir kënnen hir Operatioun kontrolléieren:
echo '13123123123123123123123213123213' | nc localhost 5046
A mir gesinn d'Äntwert an der Containerkonsole:
Awer gläichzäiteg gesi mir och:
logstash_one_channel | [2019-04-29T11:28:59,790][ERROR][logstash.licensechecker.licensereader] Kann net Lizenzinformatioun vum Lizenzserver recuperéieren {:message=>“Elasticsearch Unreachable: [http://elasticsearch:9200/][Manticore ::ResolutionFailure] elasticsearch", ...
logstash_one_channel | [2019-04-29T11:28:59,894][INFO ][logstash.pipeline ] Pipeline started successfully {:pipeline_id=>".monitoring-logstash", :thread=>"#<Thread:0x119abb86 run>»}
logstash_one_channel | [2019-04-29T11:28:59,988][INFO ][logstash.agent ] Pipelines running {:count=>2, :running_pipelines=>[:HABR, :".monitoring-logstash"], :non_running_pipelines=>[]}
logstash_one_channel | [2019-04-29T11:29:00,015][ERROR][logstash.inputs.metrics] X-Pack ass op Logstash installéiert awer net op Elasticsearch. Installéiert w.e.g. X-Pack op Elasticsearch fir d'Iwwerwaachungsfunktioun ze benotzen. Aner Funktiounen kënne verfügbar sinn.
logstash_one_channel | [2019-04-29T11:29:00,526][INFO ][logstash.agent ] Logstash API Endpunkt gestart {:port=>9600}
logstash_one_channel | [2019-04-29T11:29:04,478][INFO ][logstash.outputs.elasticsearch] Lafen Gesondheetscheck fir ze kucken ob eng Elasticsearch Verbindung funktionnéiert {:healthcheck_url=>http://elasticsearch:9200/, :path=> "/"}
logstash_one_channel | [2019-04-29T11:29:04,487][WARN ][logstash.outputs.elasticsearch] Attempted to resurrect connection to dead ES instance, but got an error. {:url=>«
logstash_one_channel | [2019-04-29T11:29:04,704][INFO ][logstash.licensechecker.licensereader] Running health check to see if an Elasticsearch connection is working {:healthcheck_url=>http://elasticsearch:9200/, :path=>"/"}
logstash_one_channel | [2019-04-29T11:29:04,710][WARN ][logstash.licensechecker.licensereader] Versicht d'Verbindung op dout ES Instanz erëmbeliewen, awer krut e Feeler. {:url=>“
An eise Logbicher kräischen déi ganzen Zäit.
Здесь я выделил зелёным цветом сообщение о том, что pipeline успешно запустилась, красным — сообщение об ошибке и жёлтым — сообщение о попытке связаться с
Dëst geschitt well logstash.conf, am Bild abegraff, e Scheck fir elasticsearch Disponibilitéit enthält. No all, iwwerhëlt logstash datt et als Deel vun der Elk Stack Wierker, mä mir getrennt et.
Et ass méiglech ze schaffen, awer et ass net bequem.
D'Léisung ass dës Scheck iwwer d'XPACK_MONITORING_ENABLED Ëmfeldvariabel auszeschalten.
Loosst eis eng Ännerung op docker-compose.yml maachen a lafen et nach eng Kéier:
version: '3'
networks:
elk:
volumes:
elasticsearch:
driver: local
services:
logstash:
container_name: logstash_one_channel
image: docker.elastic.co/logstash/logstash:6.3.2
networks:
- elk
environment:
XPACK_MONITORING_ENABLED: "false"
ports:
- 5046:5046
volumes:
- ./config/pipelines.yml:/usr/share/logstash/config/pipelines.yml:ro
- ./config/pipelines:/usr/share/logstash/config/pipelines:ro
Elo ass alles gutt. De Container ass prett fir Experimenter.
Mir kënnen erëm an der nächster Konsole tippen:
echo '13123123123123123123123213123213' | nc localhost 5046
A kuckt:
logstash_one_channel | {
logstash_one_channel | "message" => "13123123123123123123123213123213",
logstash_one_channel | "@timestamp" => 2019-04-29T11:43:44.582Z,
logstash_one_channel | "@version" => "1",
logstash_one_channel | "habra_field" => "Hello Habr",
logstash_one_channel | "host" => "gateway",
logstash_one_channel | "port" => 49418
logstash_one_channel | }
Schafft an engem Kanal
Итак, мы запустились. Теперь собственно можно уделить время настройке непосредственно logstash. Не будем пока трогать файл pipelines.yml, посмотрим, что можно получить, работая с одним каналом.
Ech muss soen datt den allgemenge Prinzip fir mat der Kanalkonfiguratiounsdatei ze schaffen ass gutt an der offizieller Handbuch beschriwwen, hei
Wann Dir op Russesch wëllt liesen, hu mir dëst benotzt
Пойдем последовательно от секции Input. Работу по tcp мы уже видели. Что ещё здесь может быть интересного?
Test Messagen mat Häerzschlag
Et gëtt sou eng interessant Geleeënheet fir automatesch Testmeldungen ze generéieren.
Fir dëst ze maachen, musst Dir den Heartbean Plugin an der Input Sektioun aktivéieren.
input {
heartbeat {
message => "HeartBeat!"
}
}
Maacht et un, fänkt un eemol pro Minutt ze kréien
logstash_one_channel | {
logstash_one_channel | "@timestamp" => 2019-04-29T13:52:04.567Z,
logstash_one_channel | "habra_field" => "Hello Habr",
logstash_one_channel | "message" => "HeartBeat!",
logstash_one_channel | "@version" => "1",
logstash_one_channel | "host" => "a0667e5c57ec"
logstash_one_channel | }
Wa mir méi dacks wëlle kréien, musse mir den Intervallparameter derbäisetzen.
Dëst ass wéi mir all 10 Sekonnen e Message kréien.
input {
heartbeat {
message => "HeartBeat!"
interval => 10
}
}
Recuperéieren Daten aus enger Datei
Ещё решили посмотреть режим file. Если нормально с файлом работает, то возможно, и агента никакого не потребуется, ну хотя бы для локального использования.
Laut der Beschreiwung soll de Betribsmodus ähnlech wéi Schwanz -f sinn, d.h. liest nei Zeilen oder, als Optioun, liest de ganze Fichier.
Also wat mir wëllen kréien:
- Mir wëllen Zeilen kréien, déi un eng Logdatei bäigefüügt ginn.
- Мы хотим получать данные, которые записываются в несколько лог файлов, при этом, иметь возможность разделить что откуда получено.
- Mir wëllen sécherstellen datt wann de Logstash nei gestart gëtt, et dës Donnéeën net erëm kritt.
- Мы хотим проверить, что если logstash отключить, а данные в файлы продолжают писаться, то, когда мы его запустим, то мы эти данные получим.
Fir den Experiment ze maachen, loosst eis eng aner Zeil op docker-compose.yml derbäisetzen, de Verzeichnis opmaachen an deem mir d'Dateien setzen.
version: '3'
networks:
elk:
volumes:
elasticsearch:
driver: local
services:
logstash:
container_name: logstash_one_channel
image: docker.elastic.co/logstash/logstash:6.3.2
networks:
- elk
environment:
XPACK_MONITORING_ENABLED: "false"
ports:
- 5046:5046
volumes:
- ./config/pipelines.yml:/usr/share/logstash/config/pipelines.yml:ro
- ./config/pipelines:/usr/share/logstash/config/pipelines:ro
- ./logs:/usr/share/logstash/input
A änneren d'Input Rubrik an habr_pipeline.conf
input {
file {
path => "/usr/share/logstash/input/*.log"
}
}
Loosst eis ufänken:
docker-compose up
Fir Logbicher ze kreéieren an ze schreiwen benotze mir de Kommando:
echo '1' >> logs/number1.log
{
logstash_one_channel | "host" => "ac2d4e3ef70f",
logstash_one_channel | "habra_field" => "Hello Habr",
logstash_one_channel | "@timestamp" => 2019-04-29T14:28:53.876Z,
logstash_one_channel | "@version" => "1",
logstash_one_channel | "message" => "1",
logstash_one_channel | "path" => "/usr/share/logstash/input/number1.log"
logstash_one_channel | }
Jo, et funktionnéiert!
Zur selwechter Zäit gesi mir datt mir automatesch de Weefeld bäigefüügt hunn. Dëst bedeit datt mir an Zukunft records dorop kënnen filteren.
Loosst eis nach eng Kéier probéieren:
echo '2' >> logs/number1.log
{
logstash_one_channel | "host" => "ac2d4e3ef70f",
logstash_one_channel | "habra_field" => "Hello Habr",
logstash_one_channel | "@timestamp" => 2019-04-29T14:28:59.906Z,
logstash_one_channel | "@version" => "1",
logstash_one_channel | "message" => "2",
logstash_one_channel | "path" => "/usr/share/logstash/input/number1.log"
logstash_one_channel | }
An elo zu engem anere Fichier:
echo '1' >> logs/number2.log
{
logstash_one_channel | "host" => "ac2d4e3ef70f",
logstash_one_channel | "habra_field" => "Hello Habr",
logstash_one_channel | "@timestamp" => 2019-04-29T14:29:26.061Z,
logstash_one_channel | "@version" => "1",
logstash_one_channel | "message" => "1",
logstash_one_channel | "path" => "/usr/share/logstash/input/number2.log"
logstash_one_channel | }
Super! D'Datei gouf opgeholl, de Wee gouf korrekt spezifizéiert, alles ass gutt.
Stop Logstash a fänkt erëm un. Loosst eis waarden. Rou. Déi. Mir kréien dës records net erëm.
An elo dat getraut Experiment.
Installéiert Logstash an ausféiert:
echo '3' >> logs/number2.log
echo '4' >> logs/number1.log
Run Logstash erëm a kuckt:
logstash_one_channel | {
logstash_one_channel | "host" => "ac2d4e3ef70f",
logstash_one_channel | "habra_field" => "Hello Habr",
logstash_one_channel | "message" => "3",
logstash_one_channel | "@version" => "1",
logstash_one_channel | "path" => "/usr/share/logstash/input/number2.log",
logstash_one_channel | "@timestamp" => 2019-04-29T14:48:50.589Z
logstash_one_channel | }
logstash_one_channel | {
logstash_one_channel | "host" => "ac2d4e3ef70f",
logstash_one_channel | "habra_field" => "Hello Habr",
logstash_one_channel | "message" => "4",
logstash_one_channel | "@version" => "1",
logstash_one_channel | "path" => "/usr/share/logstash/input/number1.log",
logstash_one_channel | "@timestamp" => 2019-04-29T14:48:50.856Z
logstash_one_channel | }
Hour! Alles gouf opgeholl.
Mä mir mussen Iech iwwer déi folgend warnen. Wann de Logstash Container geläscht gëtt (docker stop logstash_one_channel && docker rm logstash_one_channel), da gëtt näischt opgeholl. D'Positioun vun der Datei bis zu där se gelies gouf gouf am Container gespäichert. Wann Dir et vun Null leeft, akzeptéiert et nëmmen nei Linnen.
Liesen bestehend Fichieren
Допустим мы первый раз запускаем logstash, но у нас уже есть логи и мы хотели бы их обработать.
Wa mir Logstash mat der Input Sektioun lafen, déi mir uewe benotzt hunn, kréie mir näischt. Nëmmen nei Linnen ginn duerch Logstash veraarbecht.
Для того, чтобы подтянулись строки из существующих файлов, следует добавить в input секцию дополнительную строчку:
input {
file {
start_position => "beginning"
path => "/usr/share/logstash/input/*.log"
}
}
Причём, есть нюанс, это действует только на новые файлы, которые logstash ещё не видел. Для тех же файлов, что уже попадали в поле зрения logstash, он уже запомнил их размер и теперь будет брать только новые записи в них.
Loosst eis hei ophalen an d'Input Sektioun studéieren. Et ginn nach vill Optiounen, awer dat ass genuch fir eis fir weider Experimenter fir de Moment.
Routing an Daten Transformatioun
Loosst eis probéieren de folgende Problem ze léisen, loosst eis soen datt mir Messagen vun engem Kanal hunn, e puer vun hinnen sinn informativ, an e puer sinn Fehlermeldungen. Si ënnerscheede sech duerch Tag. E puer sinn INFO, anerer sinn ERROR.
Mir mussen se bei der Sortie trennen. Déi. Mir schreiwen Informatiounsmeldungen an engem Kanal, a Fehlermeldungen an engem aneren.
Fir dëst ze maachen, réckelt vun der Input Sektioun op Filter an Output.
Mat der Filtersektioun wäerte mir déi erakommen Noriicht parséieren, en Hash (Schlëssel-Wäertpairen) kréien, mat deem mir scho kënne schaffen, d.h. no Konditiounen disassemble. An an der Ausgangssektioun wäerte mir Messagen auswielen an all eenzel op säin eegene Kanal schécken.
Parsing e Message mat Grok
Fir Text Strings ze analyséieren an e Set vu Felder vun hinnen ze kréien, gëtt et e spezielle Plugin an der Filtersektioun - grok.
Не ставя себе целью дать здесь его детальное описание (за этим отсылаю к
Fir dëst ze maachen, musst Dir iwwer d'Format vun den Input Saiten entscheeden. Ech hunn se esou:
1 INFO Message1
2 Feelmeldung 2
Déi. Den Identifizéierer kënnt als éischt, dann INFO/Feeler, dann e puer Wuert ouni Raum.
Et ass net schwéier, awer et ass genuch fir de Prinzip vun der Operatioun ze verstoen.
Итак, в секции filter, в плагине grok мы должны определить паттерн для разбора наших строк.
Et wäert esou ausgesinn:
filter {
grok {
match => { "message" => ["%{INT:message_id} %{LOGLEVEL:message_type} %{WORD:message_text}"] }
}
}
Wesentlech ass et e reguläre Ausdrock. Fäerdeg Mustere gi benotzt, wéi INT, LOGLEVEL, WORD. Hir Beschreiwung, wéi och aner Mustere kënnen hei fonnt ginn
Elo, duerch dëse Filter passéiert, wäert eis String an en Hash vun dräi Felder verwandelen: message_id, message_type, message_text.
Si ginn an der Ausgangssektioun ugewisen.
Routing Messagen op d'Output Sektioun mat dem Kommando if
В секции output, как мы помним, мы собирались разделить сообщения на два потока. Одни — которые iNFO, будем выводить на консоль, а с ошибками, будем выводить в файл.
Wéi trenne mir dës Messagen? Den Zoustand vum Problem proposéiert schonn eng Léisung - schliisslech hu mir schonn en dedizéierten Message_type Feld, deen nëmmen zwee Wäerter ka huelen: INFO an ERROR. Et ass op dëser Basis datt mir e Choix maache mat der if Ausso.
if [message_type] == "ERROR" {
# Здесь выводим в файл
} else
{
# Здесь выводим в stdout
}
Eng Beschreiwung vun der Aarbecht mat Felder an Opérateuren kann an dëser Rubrik fonnt ginn
Elo iwwer déi eigentlech Conclusioun selwer.
Konsolausgang, hei ass alles kloer - stdout {}
Awer d'Ausgab op eng Datei - erënnert datt mir all dëst aus engem Container lafen a fir datt d'Datei, an där mir d'Resultat schreiwen, vu baussen zougänglech ass, musse mir dëse Verzeechnes an docker-compose.yml opmaachen.
Total:
D'Output Sektioun vun eiser Datei gesäit esou aus:
output {
if [message_type] == "ERROR" {
file {
path => "/usr/share/logstash/output/test.log"
codec => line { format => "custom format: %{message}"}
}
} else
{stdout {
}
}
}
An docker-compose.yml addéiere mer en anere Volume fir d'Ausgab:
version: '3'
networks:
elk:
volumes:
elasticsearch:
driver: local
services:
logstash:
container_name: logstash_one_channel
image: docker.elastic.co/logstash/logstash:6.3.2
networks:
- elk
environment:
XPACK_MONITORING_ENABLED: "false"
ports:
- 5046:5046
volumes:
- ./config/pipelines.yml:/usr/share/logstash/config/pipelines.yml:ro
- ./config/pipelines:/usr/share/logstash/config/pipelines:ro
- ./logs:/usr/share/logstash/input
- ./output:/usr/share/logstash/output
Mir starten et, probéieren et a gesinn eng Divisioun an zwee Streamen.
Source: will.com